diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 11:09:41 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 11:09:41 +0000 |
commit | 95c2d1cbda23a41cdf6e63520c7f0b825e63dd5b (patch) | |
tree | 06d3ffa4312e568c4157f69fe1bddaddec9bc497 /app/xlockmore/modes/clock.c | |
parent | 3928433848e2d6a9356f3d438a14b32a4f87f660 (diff) |
Importing xlockmore 5.22
Diffstat (limited to 'app/xlockmore/modes/clock.c')
-rw-r--r-- | app/xlockmore/modes/clock.c | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/app/xlockmore/modes/clock.c b/app/xlockmore/modes/clock.c new file mode 100644 index 000000000..094e9734b --- /dev/null +++ b/app/xlockmore/modes/clock.c @@ -0,0 +1,477 @@ +/* -*- Mode: C; tab-width: 4 -*- */ +/* clock --- displays an analog clock */ + +#if !defined( lint ) && !defined( SABER ) +static const char sccsid[] = "@(#)clock.c 5.00 2000/11/01 xlockmore"; + +#endif + +/*- + * Copyright (c) 1995 by Jeremie PETIT <petit@aurora.unice.fr> + * + * 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. + * + * The design was highly inspirated from 'oclock' but not the code, + * which is all mine. + * + * Revision History: + * 01-Nov-2000: Allocation checks + * 10-May-1997: Compatible with xscreensaver + * 24-Dec-1995: Ron Hitchens <ron@idiom.com> cycles range and defaults + * changed. + * 01-Dec-1995: Clock size changes each time it is displayed. + * 01-Jun-1995: Written. + */ + +#ifdef STANDALONE +#define MODE_clock +#define PROGCLASS "Clock" +#define HACK_INIT init_clock +#define HACK_DRAW draw_clock +#define clock_opts xlockmore_opts +#define DEFAULTS "*delay: 100000 \n" \ + "*count: -16 \n" \ + "*cycles: 200 \n" \ + "*size: -200 \n" \ + "*ncolors: 200 \n" +#include "xlockmore.h" /* in xscreensaver distribution */ +#else /* STANDALONE */ +#include "xlock.h" /* in xlockmore distribution */ + +#endif /* STANDALONE */ + +#ifdef MODE_clock + +ModeSpecOpt clock_opts = +{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; + +#ifdef USE_MODULES +ModStruct clock_description = +{"clock", "init_clock", "draw_clock", "release_clock", + "refresh_clock", "init_clock", (char *) NULL, &clock_opts, + 100000, -16, 200, -200, 64, 1.0, "", + "Shows Packard's clock", 0, NULL}; + +#endif + +#ifdef TM_IN_SYS_TIME +#include <sys/time.h> +#else +#include <time.h> +#endif + +#define MIN_CYCLES 50 /* shortest possible time before moving the clock */ +#define MAX_CYCLES 1000 /* longest possible time before moving the clock */ +#define CLOCK_BORDER 9 /* Percentage of the clock size for the border */ +#define HOURS_SIZE 50 /* Percentage of the clock size for hours length */ +#define MINUTES_SIZE 75 /* Idem for minutes */ +#define SECONDS_SIZE 80 /* Idem for seconds */ +#define HOURS_WIDTH 10 /* Percentage of the clock size for hours width */ +#define MINUTES_WIDTH 5 /* Idem for minutes */ +#define SECONDS_WIDTH 2 /* Idem for seconds */ +#define JEWEL_POSITION 90 /* The relative position of the jewel */ +#define JEWEL_SIZE 9 /* The relative size of the jewel */ +#define MINCLOCKS 1 +#define MINSIZE 16 /* size, minimum */ + +typedef struct { + int size; /* length of the hand */ + int width; /* width of the hand */ + unsigned long color; /* color of the hand */ +} hand; + +typedef struct { + hand hours; /* the hours hand */ + hand minutes; /* the minutes hand */ + hand seconds; /* the seconds hand */ + XPoint pos; + int size; + int radius; + int boxsize; + int jewel_size; + int jewel_position; + int border_width; + unsigned long border_color; + unsigned long jewel_color; + struct tm dd_time; +} oclock; + +typedef struct { + oclock *oclocks; + time_t d_time; + int clock_count; + int width, height; + int nclocks; + int currentclocks; + int redrawing; +} clockstruct; + +static clockstruct *clocks = (clockstruct *) NULL; + +static int +myrand(int minimum, int maximum) +{ + return ((int) (minimum + (LRAND() / MAXRAND) * (maximum + 1 - minimum))); +} + +static double +HourToAngle(oclock * oclockp) +{ + return ((M_PI * ((double) oclockp->dd_time.tm_hour + + ((double) oclockp->dd_time.tm_min / 60) + + ((double) oclockp->dd_time.tm_sec / 3600))) / 6 - M_PI_2); +} + +static double +MinutesToAngle(oclock * oclockp) +{ + return ((M_PI * ((double) oclockp->dd_time.tm_min + + ((double) oclockp->dd_time.tm_sec / 60))) / 30 - M_PI_2); +} + +static double +SecondsToAngle(oclock * oclockp) +{ + return ((M_PI * ((double) oclockp->dd_time.tm_sec) / 30) - M_PI_2); +} + +static void +DrawDisk(Display * display, Window window, GC gc, + int center_x, int center_y, int diameter) +{ + int radius = diameter / 2; + + if (diameter > 1) + XFillArc(display, window, gc, + center_x - radius, center_y - radius, + diameter, diameter, + 0, 23040); + else + XDrawPoint(display, window, gc, center_x, center_y); +} + +static void +DrawBorder(ModeInfo * mi, int clck, short int mode) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + clockstruct *cp = &clocks[MI_SCREEN(mi)]; + + + if (mode == 0) + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + else + XSetForeground(display, gc, cp->oclocks[clck].border_color); + + XSetLineAttributes(display, gc, cp->oclocks[clck].border_width, + LineSolid, CapNotLast, JoinMiter); + XDrawArc(display, MI_WINDOW(mi), gc, + cp->oclocks[clck].pos.x - cp->oclocks[clck].size / 2, + cp->oclocks[clck].pos.y - cp->oclocks[clck].size / 2, + cp->oclocks[clck].size, cp->oclocks[clck].size, + 0, 23040); +} + +static void +DrawJewel(ModeInfo * mi, int clck, short int mode) +{ + Display *display = MI_DISPLAY(mi); + GC gc = MI_GC(mi); + clockstruct *cp = &clocks[MI_SCREEN(mi)]; + + XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter); + if (mode == 0) + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + else + XSetForeground(display, gc, cp->oclocks[clck].jewel_color); + DrawDisk(display, MI_WINDOW(mi), gc, + cp->oclocks[clck].pos.x, + cp->oclocks[clck].pos.y - cp->oclocks[clck].jewel_position, + cp->oclocks[clck].jewel_size); +} + +static void +DrawHand(ModeInfo * mi, int clck, hand * h, double angle, short int mode) +{ + Display *display = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + GC gc = MI_GC(mi); + clockstruct *cp = &clocks[MI_SCREEN(mi)]; + int cosi, sinj; + + /* mode: 0 for erasing, anything else for drawing */ + if (mode == 0) + XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); + else + XSetForeground(display, gc, h->color); + XSetLineAttributes(display, gc, h->width, LineSolid, CapNotLast, JoinMiter); + DrawDisk(display, window, gc, + cp->oclocks[clck].pos.x, cp->oclocks[clck].pos.y, h->width); + cosi = (int) (cos(angle) * (double) (h->size)); + sinj = (int) (sin(angle) * (double) (h->size)); + XDrawLine(display, window, gc, + cp->oclocks[clck].pos.x, cp->oclocks[clck].pos.y, + cp->oclocks[clck].pos.x + cosi, cp->oclocks[clck].pos.y + sinj); + DrawDisk(display, window, gc, + cp->oclocks[clck].pos.x + cosi, cp->oclocks[clck].pos.y + sinj, + h->width); +} + +static void +real_draw_clock(ModeInfo * mi, int clck, short int mode) +{ + clockstruct *cp = &clocks[MI_SCREEN(mi)]; + + DrawBorder(mi, clck, mode); + DrawJewel(mi, clck, mode); + DrawHand(mi, clck, &cp->oclocks[clck].hours, + HourToAngle(&cp->oclocks[clck]), mode); + DrawHand(mi, clck, &cp->oclocks[clck].minutes, + MinutesToAngle(&cp->oclocks[clck]), mode); + DrawHand(mi, clck, &cp->oclocks[clck].seconds, + SecondsToAngle(&cp->oclocks[clck]), mode); +} + +static int +collide(clockstruct * cp, int clck) +{ + int i, d, x, y; + + for (i = 0; i < clck; i++) { + x = (cp->oclocks[i].pos.x - cp->oclocks[clck].pos.x); + y = (cp->oclocks[i].pos.y - cp->oclocks[clck].pos.y); + d = (int) sqrt((double) (x * x + y * y)); + if (d < (cp->oclocks[i].size + cp->oclocks[i].border_width + + cp->oclocks[clck].size + cp->oclocks[clck].border_width) / 2) + return i; + } + return clck; +} + +static int +new_clock_state(ModeInfo * mi, int clck) +{ + clockstruct *cp = &clocks[MI_SCREEN(mi)]; + int size = MI_SIZE(mi); + int tryit; + + for (tryit = 0; tryit < 8; tryit++) { + /* We change the clock size */ + if (size < -MINSIZE) + cp->oclocks[clck].size = NRAND(MIN(-size, MAX(MINSIZE, + MIN(cp->width, cp->height))) - MINSIZE + 1) + MINSIZE; + else if (size < MINSIZE) { + if (!size) + cp->oclocks[clck].size = MAX(MINSIZE, MIN(cp->width, cp->height)); + else + cp->oclocks[clck].size = MINSIZE; + } else + cp->oclocks[clck].size = MIN(size, MAX(MINSIZE, + MIN(cp->width, cp->height))); + + /* We must compute new attributes for the clock because its size changes */ + cp->oclocks[clck].hours.size = (cp->oclocks[clck].size * HOURS_SIZE) / 200; + cp->oclocks[clck].minutes.size = + (cp->oclocks[clck].size * MINUTES_SIZE) / 200; + cp->oclocks[clck].seconds.size = + (cp->oclocks[clck].size * SECONDS_SIZE) / 200; + cp->oclocks[clck].jewel_size = (cp->oclocks[clck].size * JEWEL_SIZE) / 200; + + cp->oclocks[clck].border_width = + (cp->oclocks[clck].size * CLOCK_BORDER) / 200; + cp->oclocks[clck].hours.width = (cp->oclocks[clck].size * HOURS_WIDTH) / 200; + cp->oclocks[clck].minutes.width = + (cp->oclocks[clck].size * MINUTES_WIDTH) / 200; + cp->oclocks[clck].seconds.width = + (cp->oclocks[clck].size * SECONDS_WIDTH) / 200; + + cp->oclocks[clck].jewel_position = + (cp->oclocks[clck].size * JEWEL_POSITION) / 200; + + cp->oclocks[clck].radius = + (cp->oclocks[clck].size / 2) + cp->oclocks[clck].border_width + 1; + + /* Here we set new values for the next clock to be displayed */ + if (MI_NPIXELS(mi) > 2) { + /* New colors */ + cp->oclocks[clck].border_color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + cp->oclocks[clck].jewel_color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + cp->oclocks[clck].hours.color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + cp->oclocks[clck].minutes.color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + cp->oclocks[clck].seconds.color = MI_PIXEL(mi, NRAND(MI_NPIXELS(mi))); + } + /* A new position for the clock */ + cp->oclocks[clck].pos.x = myrand(cp->oclocks[clck].radius, + cp->width - cp->oclocks[clck].radius); + cp->oclocks[clck].pos.y = myrand(cp->oclocks[clck].radius, + cp->height - cp->oclocks[clck].radius); + if (clck == collide(cp, clck)) + return True; + } + cp->currentclocks = clck; + return False; +} + +static void +update_clock(ModeInfo * mi, int clck) +{ + clockstruct *cp = &clocks[MI_SCREEN(mi)]; + + DrawHand(mi, clck, &cp->oclocks[clck].hours, + HourToAngle(&cp->oclocks[clck]), 0); + DrawHand(mi, clck, &cp->oclocks[clck].minutes, + MinutesToAngle(&cp->oclocks[clck]), 0); + DrawHand(mi, clck, &cp->oclocks[clck].seconds, + SecondsToAngle(&cp->oclocks[clck]), 0); + cp->d_time = time((time_t *) 0); + (void) memcpy((char *) &cp->oclocks[clck].dd_time, + (char *) localtime(&cp->d_time), + sizeof (cp->oclocks[clck].dd_time)); + DrawHand(mi, clck, &cp->oclocks[clck].hours, + HourToAngle(&cp->oclocks[clck]), 1); + DrawHand(mi, clck, &cp->oclocks[clck].minutes, + MinutesToAngle(&cp->oclocks[clck]), 1); + DrawHand(mi, clck, &cp->oclocks[clck].seconds, + SecondsToAngle(&cp->oclocks[clck]), 1); +} + +void +init_clock(ModeInfo * mi) +{ + clockstruct *cp; + int clck; + + if (clocks == NULL) { + if ((clocks = (clockstruct *) calloc(MI_NUM_SCREENS(mi), + sizeof (clockstruct))) == NULL) + return; + } + cp = &clocks[MI_SCREEN(mi)]; + + + cp->redrawing = 0; + cp->width = MI_WIDTH(mi); + cp->height = MI_HEIGHT(mi); + + MI_CLEARWINDOW(mi); + + cp->nclocks = MI_COUNT(mi); + if (cp->nclocks < -MINCLOCKS) { + /* if cp->nclocks is random ... the size can change */ + if (cp->oclocks != NULL) { + free(cp->oclocks); + cp->oclocks = (oclock *) NULL; + } + cp->nclocks = NRAND(-cp->nclocks - MINCLOCKS + 1) + MINCLOCKS; + } else if (cp->nclocks < MINCLOCKS) + cp->nclocks = MINCLOCKS; + if (cp->oclocks == NULL) { + if ((cp->oclocks = (oclock *) malloc(cp->nclocks * + sizeof (oclock))) == NULL) { + return; + } + } + + cp->clock_count = MI_CYCLES(mi); + if (cp->clock_count < MIN_CYCLES) + cp->clock_count = MIN_CYCLES; + if (cp->clock_count > MAX_CYCLES) + cp->clock_count = MAX_CYCLES; + + for (clck = 0; clck < cp->nclocks; clck++) { + /* By default, we set the clock's colors to white */ + cp->oclocks[clck].border_color = MI_WHITE_PIXEL(mi); + cp->oclocks[clck].jewel_color = MI_WHITE_PIXEL(mi); + cp->oclocks[clck].hours.color = MI_WHITE_PIXEL(mi); + cp->oclocks[clck].minutes.color = MI_WHITE_PIXEL(mi); + cp->oclocks[clck].seconds.color = MI_WHITE_PIXEL(mi); + cp->d_time = time((time_t *) 0); + } + for (clck = 0; clck < cp->nclocks; clck++) { + (void) memcpy((char *) &cp->oclocks[clck].dd_time, + (char *) localtime(&cp->d_time), + sizeof (cp->oclocks[clck].dd_time)); + } + cp->currentclocks = cp->nclocks; + for (clck = 0; clck < cp->currentclocks; clck++) + if (!new_clock_state(mi, clck)) + break; +} + +void +draw_clock(ModeInfo * mi) +{ + int clck; + clockstruct *cp; + + if (clocks == NULL) + return; + cp = &clocks[MI_SCREEN(mi)]; + if (cp->oclocks == NULL) + return; + + MI_IS_DRAWN(mi) = True; + if (++cp->clock_count >= MI_CYCLES(mi)) { + cp->clock_count = 0; + for (clck = 0; clck < cp->currentclocks; clck++) + real_draw_clock(mi, clck, 0); + cp->currentclocks = cp->nclocks; + for (clck = 0; clck < cp->currentclocks; clck++) + if (!new_clock_state(mi, clck)) + break; + for (clck = 0; clck < cp->currentclocks; clck++) + real_draw_clock(mi, clck, 1); + cp->redrawing = 0; + } else if (cp->d_time != time((time_t *) 0)) + for (clck = 0; clck < cp->currentclocks; clck++) + update_clock(mi, clck); + if (cp->redrawing) { + for (clck = 0; clck < cp->currentclocks; clck++) + real_draw_clock(mi, clck, 1); + cp->redrawing = 0; + } +} + +void +release_clock(ModeInfo * mi) +{ + if (clocks != NULL) { + int screen; + + for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) { + clockstruct *cp = &clocks[screen]; + + if (cp->oclocks != NULL) { + free(cp->oclocks); + /* cp->oclocks = (oclock *) NULL; */ + } + } + free(clocks); + clocks = (clockstruct *) NULL; + } +} + +void +refresh_clock(ModeInfo * mi) +{ + clockstruct *cp; + + if (clocks == NULL) + return; + cp = &clocks[MI_SCREEN(mi)]; + + MI_CLEARWINDOW(mi); + cp->redrawing = 1; +} + +#endif /* MODE_clock */ |