/* This is free software. See LICENSE for terms.
* Copyright 2004 - 2015, Patricia Kirk.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/user.h>
#include <sys/stat.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#if !defined (__linux__)
#include <net/if_media.h>
#endif
#if defined(__OpenBSD__)
#include <sys/socket.h>
#endif
#include <net/if.h> /* Needs sys/socket.h first on OpenBSD */
#if defined (__linux__)
#include <time.h>
#include <sys/time.h>
#endif
#include "proto.h"
#include "pixmaps.h"
extern struct global g;
extern struct data fresh;
extern Pixmap icondraw, iconmask, maindraw, mainmask;
extern Display *maindisplay;
extern Window rootwindow, iconwindow, mainwindow;
extern GC icongc, maingc;
extern int mainscreen, colordepth;
struct pixstack *iconpix=NULL, *mainpix=NULL;
char *filename=NULL;
char *colornames=NULL;
char smalbuf[SMALBUF];
/* Allocate and initialize a pixstack struct and add it to the list.
* pix->index = 0 is the background color: backxpm, tile or pixmap or pseudo trans
* = 1 is the foreground color: forexpm in the foreground color
* = 2 is the shutdown color: forexpm in #fFfF01010101
* = n is forexpm in any additional colors
* 1 and 2 are switched in the list when execShutdown() is called.
* The returned value is the position on the pixstack
* list of the font in the color requested.
*/
int pixAlloc(char *colorname) {
struct pixstack *i, *ipix=NULL, *iprev=NULL, *m, *mpix=NULL, *mprev=NULL;
int index=0, found=0;
CALLOC(ipix, 1, sizeof(struct pixstack), "pixAlloc");
CALLOC(mpix, 1, sizeof(struct pixstack), "pixAlloc");
STRDUP(ipix->colorname, colorname);
STRDUP(mpix->colorname, colorname);
if (!iconpix) {
ipix->index = index;
mpix->index = index;
iconpix = ipix;
mainpix = mpix;
} else {
i = iconpix;
m = mainpix;
while (i && m) {
iprev = i;
mprev = m;
if (!strcasecmp(i->colorname, colorname)) {
FREE(ipix->colorname);
FREE(mpix->colorname);
FREE(ipix);
FREE(mpix);
found = 1;
break;
}
i = i->next;
m = m->next;
index++;
}
if (!found) {
ipix->index = index;
mpix->index = index;
iprev->next = ipix;
mprev->next = mpix;
}
}
return index;
}
/* There's only one mask at pixlist->next.
* The others are all freed at startup
* since they're all the same.
*/
void putChar(struct lineopts *line, struct pixstack *pix, int offset, int width, int left) {
struct pixstack *list;
Pixmap mask, draw;
GC gc;
int xmag, div;
if (!g.iconized || line->panel == 1) {
if (!g.iconized) {
list = mainpix;
mask = mainmask;
draw = maindraw;
gc = maingc;
xmag = g.xmag;
div = 1;
} else {
list = iconpix;
mask = iconmask;
draw = icondraw;
gc = icongc;
xmag = 1;
div = g.xmag;
}
/* (display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y) */
if (g.pixmap)
XCopyPlane(maindisplay, list->next->mask, mask, gc,
((CHARWIDTH * xmag) * (offset % 10)),
((CHARHEIGHT * xmag) * (offset / 10)),
(width * xmag), (CHARHEIGHT * xmag),
(line->left + (left * xmag)), (line->upper / div), 1);
XCopyArea(maindisplay, pix->pixmap, draw, gc,
((CHARWIDTH * xmag) * (offset % 10)),
((CHARHEIGHT * xmag) * (offset / 10)),
(width * xmag), (CHARHEIGHT * xmag),
(line->left + (left * xmag)), (line->upper / div));
}
}
void drawSlider(struct lineopts *line) {
struct pixstack *pix, *vpix, *list;
Pixmap mask, draw;
GC gc;
int i, j, xmag, div;
static int k, l, m, init=1;
static struct pixstack *vipix, *vmpix, *ipix, *mpix;
if (init) {
/* Use the shutdown color for the
* current volume indicator.
*/
vipix = iconpix->next->next;
vmpix = mainpix->next->next;
init = line->color ? line->color : FORE;
ipix = iconpix;
mpix = mainpix;
while (init) {
ipix = ipix->next;
mpix = mpix->next;
init--;
}
k = '|' - ASCEN;
l = '.' - ASCEN;
m = 'i' - ASCEN;
}
if (!g.iconized || line->panel == 1) {
if (!g.iconized) {
list = mainpix;
pix = mpix;
vpix = vmpix;
mask = mainmask;
draw = maindraw;
gc = maingc;
xmag = g.xmag;
div = 1;
} else {
list = iconpix;
pix = ipix;
vpix = vipix;
mask = iconmask;
draw = icondraw;
gc = icongc;
xmag = 1;
div = g.xmag;
}
/* (display, src, dest, gc, src_x, src_y, width, height, dest_x, dest_y) */
putChar(line, pix, '<' - ASCEN, CHARWIDTH, 2);
/* Add a bar across the open end. */
if (g.pixmap)
XCopyPlane(maindisplay, list->next->mask, mask, gc,
((CHARWIDTH * xmag) * (k % 10)),
((CHARHEIGHT * xmag) * (k / 10)),
xmag, (CHARHEIGHT * xmag),
(line->left + (5 * xmag)), (line->upper / div), 1);
XCopyArea(maindisplay, pix->pixmap, draw, gc,
((CHARWIDTH * xmag) * (k % 10)),
((CHARHEIGHT * xmag) * (k / 10)),
xmag, (CHARHEIGHT * xmag),
(line->left + (5 * xmag)), (line->upper / div));
j = parseStrtol(line->value, TRUE, "drawSlider");
j = (fresh.volume[j] / 2) + 6 + (fresh.volume[j] > 98);
for (i = 6; i < 58; i++) {
if (i == j) {
/* Current volume level marker in red. */
putChar(line, vpix, k, 1, i);
} else if ((i - 6) && i < 50 && !((i - 6) % 10)) {
/* Make the pips. */
if (g.pixmap) {
XCopyPlane(maindisplay, list->next->mask, mask, gc,
((CHARWIDTH * xmag) * (m % 10)),
((CHARHEIGHT * xmag) * (m / 10)) + (4 * xmag),
xmag, ((CHARHEIGHT - 4) * xmag),
(line->left + (i * xmag)), (line->upper / div) + (4 * xmag), 1);
}
XCopyArea(maindisplay, pix->pixmap, draw, gc,
((CHARWIDTH * xmag) * (m % 10)),
((CHARHEIGHT * xmag) * (m / 10)) + (4 * xmag),
xmag, ((CHARHEIGHT - 4) * xmag),
(line->left + (i * xmag)), (line->upper / div) + (4 * xmag));
goto putell;
} else {
putChar(line, pix, l, 1, i);
/* The top line. */
putell:
if (g.pixmap)
XCopyPlane(maindisplay, list->next->mask, mask, gc,
((CHARWIDTH * xmag) * (l % 10)),
((CHARHEIGHT * xmag) * (l / 10)) + (6 * xmag),
xmag, xmag,
(line->left + (i * xmag)), (line->upper / div), 1);
XCopyArea(maindisplay, pix->pixmap, draw, gc,
((CHARWIDTH * xmag) * (l % 10)),
((CHARHEIGHT * xmag) * (l / 10)) + (6 * xmag),
xmag, xmag,
(line->left + (i * xmag)), (line->upper / div));
}
}
putChar(line, pix, '>' - ASCEN, CHARWIDTH, 58);
if (g.pixmap)
XCopyPlane(maindisplay, list->next->mask, mask, gc,
((CHARWIDTH * xmag) * (k % 10)),
((CHARHEIGHT * xmag) * (k / 10)),
xmag, (CHARHEIGHT * xmag),
(line->left + (58 * xmag)), (line->upper / div), 1);
XCopyArea(maindisplay, pix->pixmap, draw, gc,
((CHARWIDTH * xmag) * (k % 10)),
((CHARHEIGHT * xmag) * (k / 10)),
xmag, (CHARHEIGHT * xmag),
(line->left + (58 * xmag)), (line->upper / div));
}
}
/* Copy an updated line into the draw window.
*/
void lineToDraw(char *buffer, struct lineopts *line) {
int i, j, k[SHOWBUF], l=0, m=61, color;
struct pixstack *pix;
char showbuf[SHOWBUF];
const int charwidth[] = {
5, 5, 0, 1, 3, 5, 5, 5, 5, 1, /* 39 */
3, 3, 5, 5, 2, 4, 1, 3, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 1, 1, /* 59 */
4, 4, 4, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 3, 5, 5, 5, 5, 5, 5, /* 79 */
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 2, 3, 2, 5, 5, 2, 4, 4, 4, /* 99 */
4, 4, 4, 4, 4, 1, 4, 4, 3, 5,
4, 4, 4, 4, 4, 4, 3, 4, 5, 5, /* 119 */
5, 5, 5, 4, 1, 4, 5, 3, 0, 0
};
/* First count the unfilled columns and the
* number of blank areas indicated with PIPEs.
*/
for (i = 0; i < SHOWBUF; i++) {
if (!(j = buffer[i]))
break;
if (j == PIPE)
l++;
else
m -= (charwidth[j - 30] + 1);
if (m < 0) {
m = 0;
break;
}
}
/* There may not be a PIPE if it's a user defined line. */
if (l)
l = m / l;
else
l = m;
l += !l;
m = 2;
/* Now l is the width of a blank area and m
* is the offset of the first character.
* Calc the x offset for each of the
* other characters.
*/
for (i = 0; i < SHOWBUF; i++) {
j = buffer[i];
if (!j || m > 61)
break;
k[i] = m;
if (j == PIPE) {
m += l;
showbuf[i] = SPACE;
} else {
m += charwidth[j - 30] + 1;
showbuf[i] = j;
}
}
showbuf[i] = '\0';
color = line->color ? line->color : FORE;
if (g.iconized)
pix = iconpix;
else
pix = mainpix;
while (color) {
pix = pix->next;
color--;
}
for (i = 0; i < SHOWBUF; i++) {
if (!showbuf[i])
break;
j = charwidth[(int)showbuf[i] - 30];
while (j && ((j + k[i]) > 62))
j--;
if (!j)
continue;
l = showbuf[i] - ASCEN;
putChar(line, pix, l, j, k[i]);
}
}
void formatLine(int direct, struct lineopts *line, double value, char buffer[]) {
int display, i, j;
if (direct) {
/* Used for cpu splits, load averages and
* memory when expressed as percentage.
*/
i = strlen(buffer) - 1;
if (buffer[i] == '%')
i--;
buffer[i--] = ((int)value % 10) + AZERO; /* hundredths */
value /= 10;
buffer[i--] = ((int)value % 10) + AZERO; /* tenths */
value /= 10;
i--;
buffer[i--] = ((int)value % 10) + AZERO; /* ones */
value /= 10;
buffer[i--] = (int)value ? ((int)value % 10) + AZERO : SPACE; /* tens */
value /= 10;
buffer[i] = (int)value ? ((int)value % 10) + AZERO : SPACE; /* hundreds */
} else {
/* Used for free and used memory, free and used swap,
* share, buffer and cache memory. First determine
* the units of measure and enter it in the
* right most space if required.
*/
if (value > 999999999999LL) {
display = value / 1000 / 1000 / 1000;
i = GIGS;
} else if (value > 999999999L) {
display = value / 1000 / 1000;
i = MEGS;
} else if (value > 999999L) {
display = value / 1000;
i = KEYS;
} else {
display = value;
i = 0;
}
j = 12;
if (i)
buffer[j--] = i;
for (i = j; i > 4; i--) {
buffer[i] = (display % 10) + AZERO;
display /= 10;
if (!display)
break;
}
}
lineToDraw(buffer, line);
}
/* Write an entry into .../salmon.log.
* If logbeep is set, make a brief
* beep noise.
*/
void logMessage(char *message) {
time_t timenow=time(NULL);
struct tm *timeptr;
char buffer[BUFSIZE];
FILE *logfile;
int i, j, k;
snprintf(buffer, sizeof(buffer), "%s/salmon.log", g.tempdir);
if ((logfile = fopen(buffer, "a"))) {
timeptr = localtime(&timenow);
strftime(buffer, sizeof(buffer), "%m/%d %H:%M:%S", timeptr);
fprintf(logfile, "%s #%05d, %s.\n", buffer, (int)getpid(), message);
fclose(logfile);
}
if (g.logbeep) {
snprintf(smalbuf, SMALBUF, "%s", BEEPER);
if ((logfile = fopen(smalbuf, "w"))) {
#if defined (__OpenBSD__)
k = 350;
for (i = 0; i < 10000; i++)
#else
k = 8000;
for (i = 0; i < 500; i++)
#endif
{
j = i * k;
write(fileno(logfile), &j, 1);
}
fclose(logfile);
} else {
g.logbeep = 0;
snprintf(smalbuf, SMALBUF, "logbeep failed, %s", strerror(errno));
logMessage(smalbuf);
}
}
}
/* Used by CALLOC.
*/
void allocFailed(char *function) {
snprintf(smalbuf, SMALBUF, "%s() failed to allocate memory", function);
gdayMate(smalbuf, strerror(errno));
}
/* If message == NULL, exit(0) else exit(1)
*/
void gdayMate(char *message, char *errmsg) {
char buffer[BUFSIZE];
bzero(&buffer, BUFSIZE);
if (message)
snprintf(buffer, BUFSIZE, "%s", message);
if (errmsg) {
stringcat(buffer, ", ", BUFSIZE);
stringcat(buffer, errmsg, BUFSIZE);
}
if (strlen(buffer)) {
logMessage(buffer);
fprintf(stderr, "\nsalmon: %s.\n\n", buffer);
}
if (maindisplay)
XCloseDisplay(maindisplay);
if (message && getpid() != g.ppid)
sleep(1);
exit(message != NULL);
}
int readPixmap(struct pixstack *stack, char *name) {
stack->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
return (XpmReadFileToPixmap(maindisplay, rootwindow, name, &stack->pixmap,
&stack->mask, &stack->attributes));
}
/* colorname is the name of the color from rgb.txt
* or hash plus a six or twelve digit hex value
* rate is LITE or DARK from salmon.h, 1.00 or 0.55
*/
char *getColor(char *colorname, float rate) {
XColor color;
static char smalbuf[SMALBUF];
bzero(&color, sizeof(color));
if (!XParseColor(maindisplay, DefaultColormap(maindisplay, mainscreen), colorname, &color)) {
if (!colornames) {
CALLOC(colornames, (20 * SMALBUF), sizeof(char), "getColor");
}
if (!strstr(colornames, colorname)) {
stringcat(colornames, colorname, (20 * SMALBUF));
snprintf(smalbuf, sizeof(smalbuf), "getColor() can`t parse color \"%s\"", colorname);
logMessage(smalbuf);
}
XParseColor(maindisplay, DefaultColormap(maindisplay, mainscreen), FOREGROUND, &color);
}
if (!XAllocColor(maindisplay, DefaultColormap(maindisplay, mainscreen), &color)) {
snprintf(smalbuf, sizeof(smalbuf), "getColor() can`t allocate color \"%s\"", colorname);
logMessage(smalbuf);
}
if (rate != LITE) {
color.red *= rate;
color.green *= rate;
color.blue *= rate;
}
snprintf(smalbuf, sizeof(smalbuf), "#%04x%04x%04x", color.red, color.green, color.blue);
return smalbuf;
}
void initPixlist() {
struct pixstack *ipix=NULL, *mpix=NULL;
int width, height, i, j, k, l, xmag;
char **color, **xpm;
FILE *fd;
if (!filename) {
CALLOC(filename, BUFPLUS, sizeof(char), "initPixlist");
}
if (!(color = (char **)calloc(3 * SMALBUF, sizeof(char))))
allocFailed("initPixlist");
for (i = 0; i < 3; i++)
color[i] = (char *)calloc(SMALBUF, sizeof(char));
snprintf(filename, BUFPLUS, "%s/XXXXXX", g.tempdir);
if (mkstemp(filename) == -1)
gdayMate("initPixlist() failed to create resize tempfile", strerror(errno));
for (ipix = iconpix, mpix = mainpix; ipix && mpix; ipix = ipix->next, mpix = mpix->next) {
xmag = g.xmag;
if (g.pixmap && ipix->index)
snprintf(color[0], SMALBUF, ". c None");
else
/* This is pointing at the background colorname. */
snprintf(color[0], SMALBUF, "%s%s", xpmchars[0], getColor(iconpix->colorname, LITE));
if (!ipix->index) {
if (g.pixmap) {
FREE(ipix->colorname);
FREE(mpix->colorname);
snprintf(color[0], SMALBUF, ". c None");
snprintf(color[1], SMALBUF, "# c None");
snprintf(color[2], SMALBUF, "c c None");
if (g.panel)
xmag = g.xmag * 2;
} else {
/* Get the foreground color for the background pixmap border. */
snprintf(color[1], SMALBUF, "%s%s", xpmchars[1], getColor(iconpix->next->colorname, LITE));
snprintf(color[2], SMALBUF, "%s%s", xpmchars[2], getColor(iconpix->next->colorname, DARK));
}
xpm = backxpm;
} else {
snprintf(color[1], SMALBUF, "%s%s", xpmchars[1], getColor(ipix->colorname, LITE));
snprintf(color[2], SMALBUF, "%s%s", xpmchars[2], getColor(ipix->colorname, DARK));
xpm = forexpm;
}
/* Background or foreground xpm's from pixmaps.h */
width = (int)strtol(xpm[0], NULL, 10);
height = (int)strtol(strchr(xpm[0], ' '), NULL, 10);
for (i = 0; i < 3; i++)
xpm[i + 1] = color[i];
ipix->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
if (XpmCreatePixmapFromData(maindisplay, rootwindow, xpm, &ipix->pixmap, &ipix->mask, &ipix->attributes))
gdayMate("initPixlist() failed to create pixmap", strerror(errno));
if (xmag == 1) {
mpix->attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
if (XpmCreatePixmapFromData(maindisplay, rootwindow, xpm, &mpix->pixmap, &mpix->mask, &mpix->attributes))
gdayMate("initPixlist() failed to create pixmap", strerror(errno));
} else {
if (!(fd = fopen(filename, "w")))
gdayMate("initPixlist() failed to open resize tempfile", strerror(errno));
fprintf(fd, "/* XPM */\nstatic char *salmon[] = {\n\"%d %d 3 1\",\n",
width * xmag, height * xmag);
for (i = 0; i < 3; i++)
fprintf(fd, "\"%s\",\n", color[i]);
for (i = 0; i < height; i++) {
for (j = 0; j < xmag; j++) {
fprintf(fd, "\"");
for (k = 0; k < width; k++) {
for (l = 0; l < xmag; l++)
fprintf(fd, "%c", xpm[i + 4][k]);
}
fprintf(fd, "\",\n");
}
}
fprintf(fd, "};\n");
fclose(fd);
i = readPixmap(mpix, filename);
if (i)
gdayMate("initPixlist() failed to read resized pixmap", strerror(errno));
}
}
if (filename && unlink(filename)) {
snprintf(color[0], SMALBUF, "initPixlist() failed to remove tempfile \"%s\"", filename);
logMessage(color[0]);
}
if (g.pixmap && (ipix = iconpix->next->next) && (mpix = mainpix->next->next)) {
while (ipix && mpix) {
/* The masks are all the same. */
XFreePixmap(maindisplay, ipix->mask);
XFreePixmap(maindisplay, mpix->mask);
ipix = ipix->next;
mpix = mpix->next;
}
}
FREE(color);
FREE(colornames);
}
/* If called with background TRUE, use resize or montage
* to prepare the background pixmap. If FALSE, use to
* resize the moon graphic.
*/
void scaleGraphic(int pixmap, int background) {
int i, x, y;
char *buffer, *tilecmd=NULL;
struct stat sb;
FILE *fd;
if (!filename) {
CALLOC(filename, BUFPLUS, sizeof(char), "scaleGraphic");
}
CALLOC(buffer, BUFPLUS, sizeof(char), "scaleGraphic");
if (background) {
if (pixmap < 0)
i = snprintf(filename, BUFPLUS, "%s/t%02d.gz", g.datadir, abs(pixmap));
else
i = snprintf(filename, BUFPLUS, "%s/b%02d.gz", g.datadir, pixmap);
} else {
i = snprintf(filename, BUFPLUS, "%s/%03d.gz", g.datadir, pixmap);
}
if (i >= BUFPLUS || stat(filename, &sb) == -1) {
snprintf(buffer, BUFPLUS, "scaleGraphic() failed to stat pixmap \"%s\"", filename);
gdayMate(buffer, strerror(errno));
}
snprintf(filename, BUFSIZE, "%s/XXXXXX", g.tempdir);
if (mkstemp(filename) == -1)
gdayMate("scaleGraphic() failed to create tempfile", strerror(errno));
if (background) {
if (pixmap < 0)
snprintf(buffer, BUFPLUS, "%s %s/t%02d.gz > %s",
g.unzip, g.datadir, abs(pixmap), filename);
else
snprintf(buffer, BUFPLUS, "%s %s/b%02d.gz > %s",
g.unzip, g.datadir, pixmap, filename);
} else {
snprintf(buffer, BUFPLUS, "%s %s/%03d.gz > %s",
g.unzip, g.datadir, pixmap, filename);
}
if ((fd = popen(buffer, "r")))
pclose(fd);
else
gdayMate("scaleGraphic() failed to unzip pixmap", strerror(errno));
if (pixmap < 0) {
/* Using a tile. The size is correct for the iconpix.
* Repeat (xmag * xmag) plus one times to fill mainpix.
*/
y = readPixmap(iconpix, filename);
snprintf(buffer, BUFPLUS, "%s %dx%d ", g.tiler, g.isize, g.isize);
x = ((strlen(filename) + 1) * ((g.xmag * g.xmag) + 1)) + strlen(buffer) + 1;
CALLOC(tilecmd, x, sizeof(char), "scaleGraphic");
stringcpy(tilecmd, buffer, x);
errno = ENAMETOOLONG;
for (i = 0; i <= (g.xmag * g.xmag); i++) {
stringcat(tilecmd, " ", x);
if ((stringcat(tilecmd, filename, x)) < 0)
gdayMate("scaleGraphic() tile command line too long", strerror(errno));
}
if ((fd = popen(tilecmd, "r")))
pclose(fd);
x = readPixmap(mainpix, filename);
FREE(tilecmd);
} else {
if (g.xmag != 5) {
snprintf(buffer, BUFPLUS, "%s %dx%d %s", g.resize, g.msize, g.msize, filename);
if ((fd = popen(buffer, "r")))
pclose(fd);
else
gdayMate("scaleGraphic() resize command failed", strerror(errno));
}
if (background)
x = readPixmap(mainpix, filename);
else
x = readPixmap(mainpix->next, filename);
if (g.isize != g.msize) {
if (g.xmag != 5) {
/* The image has already been resized once.
* Get a new one rather than resize it again.
*/
if (background)
snprintf(buffer, BUFPLUS, "%s %s/b%02d.gz > %s",
g.unzip, g.datadir, pixmap, filename);
else
snprintf(buffer, BUFPLUS, "%s %s/%03d.gz > %s",
g.unzip, g.datadir, pixmap, filename);
if ((fd = popen(buffer, "r")))
pclose(fd);
else
gdayMate("scaleGraphic() resize command failed", strerror(errno));
}
snprintf(buffer, BUFPLUS, "%s %dx%d %s",
g.resize, g.isize, g.isize, filename);
if ((fd = popen(buffer, "r")))
pclose(fd);
}
if (background)
y = readPixmap(iconpix, filename);
else
y = readPixmap(iconpix->next, filename);
}
if (filename && unlink(filename)) {
snprintf(buffer, BUFPLUS, "scaleGraphic() failed to remove tempfile \"%s\"", filename);
logMessage(buffer);
}
FREE(buffer);
if (x || y)
gdayMate("scaleGraphic() failed to read pixmap", strerror(errno));
}
#if WITH_GRAPHICS
void checkMoon() {
static int init=1;
char *smalbuf;
int pixmap;
/* The moon pixmaps are 320x320 pixels. The
* main window will only be the correct size
* if g.xmag is 5. The icon window will
* always need to be reduced to 64x64.
*/
if (init) {
/* If the moon is new at init, the current pixmap
* will be 000.gz and the screen will not be refreshed
* because pixmap and fresh.pixmap will match.
* Fix it so they never match at init.
*/
fresh.pixmap = -1;
if (g.pixmap) {
XSetClipMask(maindisplay, icongc, iconpix->mask);
XSetClipMask(maindisplay, maingc, mainpix->mask);
/* These are only used once. */
XFreePixmap(maindisplay, iconpix->mask);
XFreePixmap(maindisplay, iconpix->pixmap);
XFreePixmap(maindisplay, mainpix->mask);
XFreePixmap(maindisplay, mainpix->pixmap);
}
init = 0;
}
CALLOC(smalbuf, SMALBUF, sizeof(char), "checkMoon");
/* getPhase() returns ASCEN or DSCEN and phase percent in buffer. */
getPhase(time(NULL), smalbuf);
pixmap = (int)(roundf(strtof(strchr(smalbuf, ' '), NULL)));
if ((int)strtol(smalbuf, NULL, 10) == DSCEN)
/* Returned by getPhase(). */
pixmap = 200 - pixmap;
FREE(smalbuf);
if (pixmap == fresh.pixmap)
/* The pixmap hasn`t changed so go back. */
return;
fresh.pixmap = pixmap;
scaleGraphic(fresh.pixmap, FALSE);
/* These don`t change often enough to stay
* current when the icon state is switched.
*/
XCopyArea(maindisplay, iconpix->next->pixmap, icondraw, icongc, 0, 0, g.isize, g.isize, 0, 0);
XCopyArea(maindisplay, mainpix->next->pixmap, maindraw, maingc, 0, 0, g.msize, g.msize, 0, 0);
}
#endif /* WITH_GRAPHICS */
void Redraw() {
XWindowAttributes xattribs;
XImage *ximage;
Pixmap mask;
XGetWindowAttributes(maindisplay, iconwindow, &xattribs);
g.iconized = xattribs.map_state;
if (g.iconized) {
if (g.pixmap) {
if (!g.moongraphic) {
ximage = XGetImage(maindisplay, iconmask, 0, 0, g.isize, g.isize, colordepth, XYPixmap);
mask = XCreateBitmapFromData(maindisplay, iconwindow, ximage->data, g.isize, g.isize);
XDestroyImage(ximage);
XSetClipMask(maindisplay, icongc, mask);
XFreePixmap(maindisplay, mask);
}
XClearWindow(maindisplay, iconwindow);
}
XCopyArea(maindisplay, icondraw, iconwindow, icongc, 0, 0, g.isize, g.isize, 0, 0);
} else {
if (g.pixmap) {
if (!g.moongraphic) {
ximage = XGetImage(maindisplay, mainmask, 0, 0, g.msize, g.msize, colordepth, XYPixmap);
mask = XCreateBitmapFromData(maindisplay, mainwindow, ximage->data, g.msize, g.msize);
XDestroyImage(ximage);
XSetClipMask(maindisplay, maingc, mask);
XFreePixmap(maindisplay, mask);
}
XClearWindow(maindisplay, mainwindow);
}
XCopyArea(maindisplay, maindraw, mainwindow, maingc, 0, 0, g.msize, g.msize, 0, 0);
}
g.updaterequest = 0;
}
void Update() {
time_t timenow=time(NULL);
if (g.refresh && (timenow - fresh.timeofdata) >= g.refresh) {
fresh.timeofdata = timenow - (timenow % g.refresh);
#if WITH_TIMESYNC
if (g.timeport && !g.timeserver)
checkSync();
#endif /* WITH_TIMESYNC */
g.updaterequest = 1;
}
checkEvents();
#if WITH_REMEXEC || WITH_TIMESYNC
/* Check for execute requests and if
* time server, check the request queue.
*/
checkSocket();
#endif /* WITH_REMEXEC || WITH_TIMESYNC */
checkEcho();
#if WITH_CONTROL
checkCtl();
#endif /* WITH_CONTROL */
if (g.updaterequest) {
#if WITH_GRAPHICS
if (g.moongraphic)
checkMoon();
else
#endif /* WITH_GRAPHICS */
checkLines();
Redraw();
}
}