summaryrefslogtreecommitdiff
path: root/app/xlockmore/modes/clock.c
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 11:09:41 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 11:09:41 +0000
commit95c2d1cbda23a41cdf6e63520c7f0b825e63dd5b (patch)
tree06d3ffa4312e568c4157f69fe1bddaddec9bc497 /app/xlockmore/modes/clock.c
parent3928433848e2d6a9356f3d438a14b32a4f87f660 (diff)
Importing xlockmore 5.22
Diffstat (limited to 'app/xlockmore/modes/clock.c')
-rw-r--r--app/xlockmore/modes/clock.c477
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 */