Return to Home page [Home].
/* $Id: analogclock.ca,v 1.26 2017/04/27 17:53:20 rkiesling Exp $ */ /* This file is part of analogclock. Copyright © 2016 Robert Kiesling, rk3314042@gmail.com. Permission is granted to copy this software provided that this copyright notice is included in all source code modules. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA. */ #include <math.h> Circle new rim; Pen new rimPen; Integer new centerX; Integer new centerY; Integer new radius; Integer new winWidth; Integer new winHeight; Integer new displayWidth; Integer new displayHeight; Boolean new fullScreen; List new tickMarks; Pen new tickPen; Integer new hoursLength; Integer new minutesLength; Integer new secondsLength; Pen new secondsPen; Pen new minutePen; Pen new hourPen; Integer new displayAlpha; String new xFontDescStr; String new ftFontDescStr; Float new ftFontPtSize; Boolean new useFTFonts; Boolean new displayText; Application new clockApp; #define SECONDS_LENGTH (radius - (rimPen width / 2) - 1) #define SECONDS_WIDTH (radius * 0.02) #define HOURS_LENGTH (radius * 0.5) #define HOURS_WIDTH (radius * 0.05) #define MINUTES_LENGTH (radius * 0.7) #define MINUTES_WIDTH (radius * 0.04) /* How far from the center a tickmark begins. These dimensions are given as a fraction of the clock's radius. */ #define BIG_TICK_START_PCT 0.85 #define SMALL_TICK_START_PCT 0.90 /* Width of the rim's border. */ #define RIM_WIDTH (radius * 0.04) #define RIM_WIDTH_FULLSCREEN (radius * 0.02) /* Margin between the rim and the edge of the window. */ #define WIN_MARGIN RIM_WIDTH /* Pixels of space between the rim's centerline and the outer end of a tick mark. */ #define TICK_MARGIN (RIM_WIDTH + (RIM_WIDTH * 0.2)) #define TICK_MARGIN_FULLSCREEN (RIM_WIDTH) /* Default window dimensions. */ #define WIN_WIDTH 200 #define WIN_HEIGHT 200 #define WIN_X 10 #define WIN_Y 10 /* From the #defines in X11/keysymdef.h */ #define X_Escape_keycode 0xff1b #define X_Control_L_keycode 0xffe3 #define X_Control_R_keycode 0xffe4 #define CTRL_C 3 /* The default alpha value and the alpha limit. */ #define DEFAULT_ALPHA 0x8888 #define OPAQUE 0xffff; #define DEFAULT_HAND_COLOR "slategray4" #define DEFAULT_RIM_COLOR "darkslategray" /* * Font stuff */ X11Font new xFont; X11FreeTypeFont new ftFont; Integer new air; /* Freetype outline fonts. The default font(s) are Type 1, and are in the ghostscript package(s). DejaVu is often included in distros as a package of its own. */ #define DEFAULT_FT_FONT "Nimbus Sans L" #define FALLBACK_FT_FONT "DejaVu Sans" /* If you prefer an arty look, uncomment this line. */ /* #define BAUHAUSE */ #ifdef BAUHAUS #undef DEFAULT_FT_FONT #define DEFAULT_FT_FONT "URW Gothic L" #endif /* X bitmap fonts. */ #define DEFAULT_X_FONT "fixed" /* These are mostly for testing. */ #define DEFAULT_X_SANS_FONT "-*-helvetica-bold-r-*-*-14-140-*-*-*-*-*-*" #define DEFAULT_X_MONO_FONT "-*-courier-medium-r-*-*-*-120-*-*-*-*-*-*" /* For use in full screen mode. */ #define BIG_X_SANS_FONT "-*-helvetica-medium-r-*-*-*-240-*-*-*-*-*-*" /* The amount of space between the font baseline and the vertical center of the window. */ #define VERT_AIR_PCT_XFONT 0.2 #define VERT_AIR_PCT_FTFONT 0.15 #define DEFAULT_TEXT_COLOR "tan" /* The center hub stuff. */ #define HUB_DIAMETER_PCT 0.04 #define AXLE_DIAMETER_PCT 0.01 String new bgColor; String new rimColor; String new geomString; Boolean new displaySeconds; Boolean new displayRim; Boolean new displayTickMarks; String new secondHandColor; String new minuteHandColor; String new hourHandColor; String new tickColor; String new textColor; void exit_help (char *); #ifdef APPLE /* If Ctalk on your machine orders things differently than what the MacOslinker prefers, then the program might need these in libctalk (in xrender.c), *even if they're declared static*. (At least mine does.) You might need to adjust this define - YMMV. */ double degree_to_radian (double); double opp_side (double, double); double adj_side (double, double); #else double degree_to_radian (double d) { double radians; radians = d * (3.1416 / 180); return radians; } double opp_side (double deg, double hyp) { return hyp * sin(degree_to_radian (deg)); } double adj_side (double deg, double hyp) { return hyp * cos(degree_to_radian (deg)); } #endif /* #ifdef APPLE */ CTime instanceMethod getUTCTime (void) { self utcTime; return self; } AssociativeArray new weekDayNames; Application instanceMethod initDateStuff (void) { weekDayNames = 0, "Sunday", 1, "Monday", 2, "Tuesday", 3, "Wednesday", 4, "Thursday", 5, "Friday", 6, "Saturday", 7, "Sunday"; if (displayText) xFont getFontInfo xFontDescStr; } Application instanceMethod faceDimensions (void) { centerX = self winWidth / 2; centerY = self winHeight / 2; if (self winWidth > self winHeight) { radius = (self winHeight / 2); if (displayText) { if (useFTFonts) { if (fullScreen) { air = self winHeight * VERT_AIR_PCT_XFONT; } else { air = self winHeight * VERT_AIR_PCT_FTFONT; } } else { air = self winHeight * VERT_AIR_PCT_XFONT; } } } else { radius = (self winWidth / 2); if (displayText) { if (useFTFonts) { air = self winWidth * VERT_AIR_PCT_FTFONT; } else { air = self winWidth * VERT_AIR_PCT_XFONT; } } } radius -= WIN_MARGIN; rim center x = centerX; rim center y = centerY; rim radius = radius; rimPen colorName = rimColor; if (fullScreen) rimPen width = RIM_WIDTH_FULLSCREEN; else rimPen width = RIM_WIDTH; rimPen alpha = displayAlpha; tickMarks delete; } X11CanvasPane instanceMethod printDate (Integer dayOfMonth, Integer dayOfWeek, Integer winWidth, Integer winHeight) { String new buf; Integer new dateY; Integer new dateX; Integer new textWidth; dateY = winHeight / 2; dateY -= air; buf printOn "%s %d", (weekDayNames at dayOfWeek), dayOfMonth; if (useFTFonts) { textWidth = ftFont textWidth buf; } else { textWidth = xFont textWidth buf; } dateX = winWidth / 2; dateX -= (textWidth / 2); self putStrXY dateX, dateY, buf, (xFont fontDesc), textColor; } X11CanvasPane instanceMethod drawTime (Integer seconds, Integer minutes, Integer hours) { double theta; Integer new endX; Integer new endY; Integer new hub_adj; Integer new short_side; if (hours >= 12) { theta = ((hours - 12) * 30) - 90; } else { theta = (hours * 30) - 90; } theta += (minutes * 6) / 12; endX = (int)adj_side (theta, hoursLength); endX += centerX; endY = (int) opp_side (theta, hoursLength); endY += centerY; self pen alpha = displayAlpha; self drawLine centerX, centerY, endX, endY, hourPen; theta = (minutes * 6) - 90; endX = (int) adj_side (theta, minutesLength); endX += centerX; endY = (int) opp_side (theta, minutesLength); endY += centerY; self drawLine centerX, centerY, endX, endY, minutePen; if (displaySeconds) { theta = (seconds * 6) - 90; endX = (int) adj_side (theta, secondsLength); endX += centerX; endY = (int) opp_side (theta, secondsLength); endY += centerY; self drawLine centerX, centerY, endX, endY, secondsPen; } if (winWidth < winHeight) short_side = winWidth; else short_side = winHeight; if (short_side > 125) { self pen width = short_side * HUB_DIAMETER_PCT; self pen colorName = minuteHandColor; if (self usingXRender) { self pen alpha = 0xffff; self drawPoint rim center x, rim center y; } else { hub_adj = (self pen width) / 2; self drawPoint (rim center x - hub_adj), (rim center y - hub_adj); } if (short_side > 150) { self pen width = short_side * AXLE_DIAMETER_PCT; self pen colorName = "black"; if (self usingXRender) { self pen alpha = 0xffff; self drawPoint rim center x, rim center y; } else { hub_adj = (self pen width) / 2; self drawPoint (rim center x - hub_adj), (rim center y - hub_adj); } } } } X11CanvasPane instanceMethod initFace (Integer centerX, Integer centerY, Integer radius) { double d, d_r, d_t; int d_adj, d_opp, d_int; Symbol new tickPtr; /***/ /* rim center x = centerX; rim center y = centerY; rim radius = radius; */ /* rimPen colorName = rimColor; if (fullScreen) rimPen width = RIM_WIDTH_FULLSCREEN; else rimPen width = RIM_WIDTH; */ /* rimPen alpha = displayAlpha; */ if (displayTickMarks) { d_r = radius; for (d = 0; d < 360; d += 1.0) { d_int = d; if ((d_int % 6) == 0) { if ((d_int % 30) == 0) { d_t = d + 90.0; *tickPtr = Line basicNew "tickMark"; d_adj = (int)adj_side (d_t, (BIG_TICK_START_PCT * d_r)); d_opp = (int) opp_side (d_t, (BIG_TICK_START_PCT * d_r)); (*tickPtr) start x = centerX + d_adj; (*tickPtr) start y = centerY + d_opp; if (fullScreen) { d_adj = (int)adj_side (d_t, (d_r - TICK_MARGIN_FULLSCREEN)); d_opp = (int) opp_side (d_t, (d_r - TICK_MARGIN_FULLSCREEN)); } else { d_adj = (int)adj_side (d_t, (d_r - TICK_MARGIN)); d_opp = (int) opp_side (d_t, (d_r - TICK_MARGIN)); } (*tickPtr) end x = centerX + d_adj; (*tickPtr) end y = centerY + d_opp; tickMarks push *tickPtr; } else { d_t = d + 90.0; *tickPtr = Line basicNew "tickMark"; d_adj = (int)adj_side (d_t, (SMALL_TICK_START_PCT * d_r)); d_opp = (int) opp_side (d_t, (SMALL_TICK_START_PCT * d_r)); (*tickPtr) start x = centerX + d_adj; (*tickPtr) start y = centerY + d_opp; if (fullScreen) { d_adj = (int)adj_side (d_t, (d_r - TICK_MARGIN_FULLSCREEN)); d_opp = (int) opp_side (d_t, (d_r - TICK_MARGIN_FULLSCREEN)); } else { d_adj = (int)adj_side (d_t, (d_r - TICK_MARGIN)); d_opp = (int) opp_side (d_t, (d_r - TICK_MARGIN)); } (*tickPtr) end x = centerX + d_adj; (*tickPtr) end y = centerY + d_opp; tickMarks push *tickPtr; } } } } tickPen width = 1; tickPen colorName = tickColor; tickPen alpha = displayAlpha; secondsLength = SECONDS_LENGTH; minutesLength = MINUTES_LENGTH; hoursLength = HOURS_LENGTH; secondsPen width = SECONDS_WIDTH; secondsPen colorName = secondHandColor; secondsPen alpha = displayAlpha; minutePen width = MINUTES_WIDTH; minutePen colorName = minuteHandColor; minutePen alpha = displayAlpha; hourPen width = HOURS_WIDTH; hourPen colorName = hourHandColor; hourPen alpha = displayAlpha; } X11CanvasPane instanceMethod drawFace (Integer centerX, Integer centerY, Integer radius) { self clear; if (displayRim) { rimPen alpha = 0xffff; self drawCircle rim, rimPen, FALSE, bgColor; } if (displayTickMarks) { tickMarks map { tickPen alpha = displayAlpha; super drawLine self, tickPen; } } } Application instanceMethod clockOptions (void) { Integer new i; Integer new nParams; String new param; nParams = self cmdLineArgs size; for (i = 1; i < nParams; i++) { param = self cmdLineArgs at i; if (param == "-g") { geomString = self cmdLineArgs at i + 1; i = i + 1; continue; } if (param == "-bg") { bgColor = self cmdLineArgs at i + 1; i = i + 1; continue; } if (param == "-rc") { rimColor = self cmdLineArgs at i + 1; i += 1; continue; } if (param == "-sh") { secondHandColor = self cmdLineArgs at i + 1; i += 1; continue; } if (param == "-mh") { minuteHandColor = self cmdLineArgs at i + 1; i += 1; continue; } if (param == "-hh") { hourHandColor = self cmdLineArgs at i + 1; i += 1; continue; } if (param == "-st") { tickColor = self cmdLineArgs at i + 1; displayTickMarks = true; i += 1; continue; } if (param == "-fc") { displayText = true; textColor = self cmdLineArgs at i + 1; i += 1; continue; } if (param == "-fn") { displayText = true; if (useFTFonts) { ftFontDescStr = self cmdLineArgs at i + 1; } else { xFontDescStr = self cmdLineArgs at i + 1; } i += 1; continue; } if (param == "-pt") { displayText = true; if (useFTFonts) ftFontPtSize = (self cmdLineArgs at i + 1) asFloat; i += 1; continue; } if (param == "-norender") { self useXRender false; continue; } if (param == "-xfonts") { useFTFonts = False; displayText = true; continue; } if (param == "-ns") { displaySeconds = FALSE; continue; } if (param == "-nr") { displayRim = FALSE; continue; } if (param == "-t") { displayTickMarks = TRUE; continue; } if (param == "-noalpha") { displayAlpha = OPAQUE; continue; } if (param == "-nt") { displayText = False; continue; } if (param == "-fullscreen") { fullScreen = true; continue; } if ((param == "-h") || (param == "--help")) exit_help ("analogclock"); printf ("analogclock: Unknown option: %s. Exiting.\n", param); exit_help ("analogclock"); } } Application instanceMethod findFonts (void) { Integer new result; if (useFTFonts && displayText) { ftFont initFontLib; if (fullScreen == true) { if (ftFontPtSize == 0.0) { result = ftFont selectFont ftFontDescStr, 0, 80, 72, 24.0; } else { result = ftFont selectFont ftFontDescStr, 0, 80, 72, ftFontPtSize; } } else { if (ftFontPtSize == 0.0) { result = ftFont selectFont ftFontDescStr, 0, 80, 72, 16.0; } else { result = ftFont selectFont ftFontDescStr, 0, 80, 72, ftFontPtSize; } } if (result == 0) { ftFont alpha DEFAULT_ALPHA; } else { printf ("analogclock: Could not find the font, \"%s.\" " "Trying the font, \"%s.\"\n", ftFontDescStr, FALLBACK_FT_FONT); ftFontDescStr = FALLBACK_FT_FONT; if (fullScreen == true) { if (ftFontPtSize == 0.0) { result = ftFont selectFont ftFontDescStr, 0, 80, 72, 24.0; } else { result = ftFont selectFont ftFontDescStr, 0, 80, 72, ftFontPtSize; } } else { if (ftFontPtSize == 0.0) { result = ftFont selectFont ftFontDescStr, 0, 80, 72, 16.0; } else { result = ftFont selectFont ftFontDescStr, 0, 80, 72, ftFontPtSize; } } if (result == 0) { ftFont alpha DEFAULT_ALPHA; } else { printf ("analogclock: Could not find the font, \"%s.\" " "Using a bitmapped font.\n", FALLBACK_FT_FONT); useFTFonts = false; if (fullScreen == true) { xFontDescStr = BIG_X_SANS_FONT; } } } ftFont namedX11Color textColor; } else if (displayText) { if (fullScreen == true) { xFontDescStr = BIG_X_SANS_FONT; } } } int main (int argc, char **argv) { X11Pane new xPane; InputEvent new e; X11PaneDispatcher new xTopLevelPane; X11CanvasPane new xCanvasPane; Integer new prevSeconds; CalendarTime new timeNow; Boolean new control_keypress; clockApp enableExceptionTrace; /* Handles Control-C's in the xterm. */ clockApp installExitHandlerBasic; displaySeconds = True; displayRim = True; displayTickMarks = False; rimColor = DEFAULT_RIM_COLOR; bgColor = "black"; secondHandColor = DEFAULT_HAND_COLOR; minuteHandColor = DEFAULT_HAND_COLOR; hourHandColor = DEFAULT_HAND_COLOR; tickColor = DEFAULT_RIM_COLOR; textColor = DEFAULT_TEXT_COLOR; displayAlpha = DEFAULT_ALPHA; ftFontDescStr = DEFAULT_FT_FONT; xFontDescStr = DEFAULT_X_FONT; useFTFonts = True; displayText = True; fullScreen = false; ftFontPtSize = 0.0; control_keypress = false; clockApp parseArgs argc, argv; clockApp clockOptions; /* Make sure we have a reasonable Xft (and X Render) installation.*/ if (ftFont version < 10) { useFTFonts = false; } if (useFTFonts) { clockApp findFonts; } if (fullScreen == true) { clockApp winWidth = xPane displayWidth; clockApp winHeight = xPane displayHeight; clockApp winXOrg = 0; clockApp winYOrg = 0; } else if (geomString length > 0) { clockApp parseX11Geometry geomString; if (clockApp winWidth == 0) { clockApp winWidth = WIN_WIDTH; } if (clockApp winHeight == 0) { clockApp winHeight = WIN_HEIGHT; } if (clockApp winXOrg == 0) { clockApp winXOrg = WIN_X; } if (clockApp winYOrg == 0) { clockApp winYOrg = WIN_Y; } } else { clockApp winWidth = WIN_WIDTH; clockApp winHeight = WIN_HEIGHT; clockApp winXOrg = WIN_X; clockApp winYOrg = WIN_Y; } xPane borderWidth = 0; winWidth = clockApp winWidth; winHeight = clockApp winHeight; /* Some of the graphics do not (yet) allow for resizing bufers. */ xPane inputStream eventMask = KEYPRESS|WINDELETE|RESIZENOTIFY; xPane initialize clockApp winXOrg, clockApp winYOrg, clockApp winWidth, clockApp winHeight, clockApp geomFlags; xTopLevelPane attachTo xPane; xCanvasPane attachTo xTopLevelPane; xPane setResources "analogClock", "AnalogClock"; xPane map; xPane raiseWindow; xPane openEventStream; xPane setWMTitle "Analog Clock"; clockApp initDateStuff; xCanvasPane background bgColor; clockApp faceDimensions; xCanvasPane initFace centerX, centerY, radius; while (TRUE) { timeNow getUTCTime; timeNow localTime; if (timeNow seconds != prevSeconds) { xCanvasPane drawFace centerX, centerY, radius; if (displayText) { xCanvasPane faceRegular; xCanvasPane printDate timeNow dom, timeNow dow, clockApp winWidth, clockApp winHeight; } xCanvasPane drawTime timeNow seconds, timeNow minutes, timeNow hours; xCanvasPane refresh; prevSeconds = timeNow seconds; xPane inputStream queueInput; if (xPane inputStream eventPending) { e become xPane inputStream inputQueue unshift; xPane subPaneNotify e; /* Call the classes' built-in event handlers. */ switch (e eventClass value) { case WINDELETE: xPane deleteAndClose; exit (0); break; case RESIZENOTIFY: clockApp winWidth = e xEventData3; clockApp winHeight = e xEventData4; clockApp faceDimensions; xCanvasPane background bgColor; xCanvasPane clear; xCanvasPane initFace centerX, centerY, radius; xCanvasPane refresh; break; case KEYPRESS: /* Escape or Control-C key closes the window. X11CanvasPane objects don't have a built-in keyboard handler, so there's one here. */ if (e xEventData5 value == X_Escape_keycode) { /* tickMarks delete; */ xPane deleteAndClose; exit (0); } else if (e xEventData5 == X_Control_L_keycode || e xEventData5 == X_Control_R_keycode) { control_keypress = true; continue; } else if (control_keypress) { if (e xEventData5 == CTRL_C) { /* tickMarks delete; */ xPane deleteAndClose; exit (0); } else { control_keypress = false; } } else { control_keypress = false; } break; default: break; } } } clockApp uSleep 100000; } } void exit_help (char *cmd) { printf ("\nUsage: %s [-h] | [-noalpha] [-norender] [-nr] [-ns] [-nt] [-pt <ptsize>] [-st] [-t] [-xfonts] [-fullscreen] [-bg <color>] [-fc <color>] [-hh <color>] [-mh <color>] [-rc <color>] [-sh <color>] [-st <color>] [-fn <font>] [-g <geom>]\n", cmd); printf ("-bg <color> Background color.\n"); printf ("-fc <color> Text foreground color.\n"); printf ("-g <geom> Initial window size and position\n"); printf ("-fn <font> Use <font> to display text - Refer to analogclock(1) for details.\n"); printf ("-fullscreen Tell the clock to occupy the entire screen. Pressing [Escape] or\n"); printf (" [Control-C] closes the window and exits the program.\n"); printf ("-h Print this message and exit.\n"); printf ("-hh <color> Hour hand color.\n"); printf ("-mh <color> Minute hand color.\n"); printf ("-noalpha Don't use alpha blending.\n"); printf ("-norender Don't use the X Render extension to draw graphics.\n"); printf ("-nr Don't display the rim.\n"); printf ("-ns Don't display the second hand.\n"); printf ("-nt Don't display the day and date.\n"); printf ("-pt <ptSize> The height of the text in points. This is only needed for\n"); printf (" outline fonts; X bitmap fonts have the font size included\n"); printf (" in the fontspec.\n"); printf ("-rc <color> Rim color.\n"); printf ("-sh <color> Second hand color.\n"); printf ("-st <color> Tick mark color. (Sets -t option.)\n"); printf ("-t Display tick marks.\n"); printf ("-xfonts Use bitmap fonts, even if outline fonts are available.\n"); printf ("Please report bugs to: rk3314042@gmail.com.\n"); exit (0);
Return to Home Page [Home].