/* -*- Mode: C; fill-column: 79 -*- ******************************************* ******************************************************************************* pclock -- a simple analog clock program for the X Window System Copyright (C) 1998 Alexander Kourakos Time-stamp: <1998-05-28 21:27:58 awk@oxygene.vnet.net> 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author: Alexander Kourakos Email: Alexander@Kourakos.com Web: http://www.kourakos.com/~awk/pclock/ ******************************************************************************* ******************************************************************************/ #include #include #include #include #include #include #include #include #include "PClock.h" /*****************************************************************************/ /* * The name of the XPM should be ``clock_background''. */ #include "Default.xpm" /*****************************************************************************/ static Display *display; static Window root, window, icon_window, main_window; static GC gc; static Atom wm_delete_window; static Pixel back_pixel, hand_pixel, second_hand_pixel; static Pixmap back_pm, mask_pm, all_pm; static int old_hour = 0, old_minute = 0, old_second = 0; /*****************************************************************************/ static Pixel GetColor(char *); static void Redraw(void); /*****************************************************************************/ void CreateWindow(int ac, char *av[]) { int zero = 0; char *app_name = NAME; char *app_class = CLASS; int screen; XSizeHints size_hints; XWMHints wm_hints; XClassHint class_hints; XTextProperty window_name; XGCValues gcv; unsigned long gcm; int result, use_internal_pixmap; size_hints.flags = PMinSize | PMaxSize | PPosition; size_hints.min_width = size_hints.max_width = size_hints.min_height = size_hints.max_height = SIZE; display = XOpenDisplay(NULL); if (display == NULL) { fprintf(stderr, "ERR: could not open display ``%s''..Exiting.\n", XDisplayName(NULL)); exit(EXIT_FAILURE); } wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", FALSE); screen = DefaultScreen(display); root = RootWindow(display, screen); back_pixel = GetColor("black"); hand_pixel = GetColor(option.hand_color); second_hand_pixel = GetColor(option.second_hand_color); use_internal_pixmap = TRUE; if (option.background_pixmap[0] != '\0') { XpmAttributes attributes; attributes.valuemask = XpmSize; result = XpmReadFileToPixmap(display, root, option.background_pixmap, &back_pm, &mask_pm, &attributes); if (result != XpmSuccess) fprintf(stderr, "ERR: trouble loading pixmap\n"); else if (attributes.width != SIZE || attributes.height != SIZE) fprintf(stderr, "ERR: pixmap must be %dx%d\n", SIZE, SIZE); else use_internal_pixmap = FALSE; } if (use_internal_pixmap) { result = XpmCreatePixmapFromData(display, root, clock_background, &back_pm, &mask_pm, NULL); if (result != XpmSuccess) { if (result == XpmColorFailed) fprintf(stderr, "ERR: unable to allocate pixmap colors..exiting\n"); else fprintf(stderr, "ERR: trouble using built-in pixmap..exiting\n"); exit(EXIT_FAILURE); } } all_pm = XCreatePixmap(display, root, SIZE, SIZE, DefaultDepth(display, screen)); XWMGeometry(display, screen, "", NULL, 0, &size_hints, &zero, &zero, &size_hints.width, &size_hints.height, &zero); window = XCreateSimpleWindow(display, root, 0, 0, size_hints.width, size_hints.height, 0, back_pixel, back_pixel); icon_window = XCreateSimpleWindow(display, root, 0, 0, size_hints.width, size_hints.height, 0, back_pixel, back_pixel); wm_hints.window_group = window; if (option.under_windowmaker) { wm_hints.initial_state = WithdrawnState; wm_hints.icon_window = icon_window; wm_hints.icon_x = wm_hints.icon_y = 0; wm_hints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; main_window = icon_window; } else { wm_hints.initial_state = NormalState; wm_hints.flags = StateHint | WindowGroupHint; main_window = window; } XSetWMNormalHints(display, window, &size_hints); class_hints.res_name = app_name; class_hints.res_class = app_class; XSetClassHint(display, window, &class_hints); XSetClassHint(display, icon_window, &class_hints); XSelectInput(display, main_window, ExposureMask | StructureNotifyMask); if (XStringListToTextProperty(&app_name, 1, &window_name) == 0) { fprintf(stderr, "ERR: can't allocate window name..exiting\n"); exit(EXIT_FAILURE); } XSetWMName(display, window, &window_name); gcm = GCForeground | GCBackground | GCGraphicsExposures; gcv.foreground = hand_pixel; gcv.background = back_pixel; gcv.graphics_exposures = 0; gc = XCreateGC(display, root, gcm, &gcv); XSetWMHints(display, window, &wm_hints); XStoreName(display, window, app_name); XSetIconName(display, window, app_name); XSetCommand(display, window, av, ac); XSetWMProtocols(display, main_window, &wm_delete_window, 1); XSetWindowBackgroundPixmap(display, main_window, back_pm); XShapeCombineMask(display, main_window, ShapeBounding, 0, 0, mask_pm, ShapeSet); XMapWindow(display, window); } /*****************************************************************************/ void DestroyWindow(void) { XFreeGC(display, gc); XFreePixmap(display, all_pm); XFreePixmap(display, back_pm); XFreePixmap(display, mask_pm); XDestroyWindow(display, window); XDestroyWindow(display, icon_window); XCloseDisplay(display); } /*****************************************************************************/ void UpdateClock(void) { int h = old_hour, m = old_minute, s; struct tm *time_struct; time_t curtime; double angle; int hx, hy, mx, my, sx, sy; curtime = time(NULL); time_struct = localtime(&curtime); h = time_struct->tm_hour; m = time_struct->tm_min; s = time_struct->tm_sec; /* * Even if we aren't showing the second hand, redraw anyway so a lost * X connection can be detected relatively quickly. */ if (h == old_hour && m == old_minute && s == old_second) return; XCopyArea(display, back_pm, all_pm, gc, 0, 0, SIZE, SIZE, 0, 0); angle = (M_PI / 6.0) * (double) h + (M_PI / 360.0) * (double) m; hx = (SIZE / 2) + (int) ((double) option.hour_hand_length * sin(angle)); hy = (SIZE / 2) - (int) ((double) option.hour_hand_length * cos(angle)); angle = (M_PI / 30.0) * (double) m; mx = (SIZE / 2) + (int) ((double) option.minute_hand_length * sin(angle)); my = (SIZE / 2) - (int) ((double) option.minute_hand_length * cos(angle)); XSetLineAttributes(display, gc, option.hand_width, LineSolid, CapRound, JoinRound); XDrawLine(display, all_pm, gc, SIZE / 2, SIZE / 2, hx, hy); XDrawLine(display, all_pm, gc, SIZE / 2, SIZE / 2, mx, my); if (option.show_seconds) { angle = (M_PI / 30.0) * (double) s; sx = (SIZE / 2) + (int) ((double) option.second_hand_length * sin(angle)); sy = (SIZE / 2) - (int) ((double) option.second_hand_length * cos(angle)); XSetForeground(display, gc, second_hand_pixel); XSetLineAttributes(display, gc, option.second_hand_width, LineSolid, CapRound, JoinRound); XDrawLine(display, all_pm, gc, SIZE / 2, SIZE / 2, sx, sy); XSetForeground(display, gc, hand_pixel); } Redraw(); old_hour = h; old_minute = m; old_second = s; } /*****************************************************************************/ void HandleEvents(int *should_quit) { XEvent event; *should_quit = FALSE; while (XPending(display)) { XNextEvent(display, &event); switch (event.type) { case Expose: if (event.xexpose.count == 0) Redraw(); break; case DestroyNotify: *should_quit = TRUE; break; case ClientMessage: if (event.xclient.data.l[0] == wm_delete_window) *should_quit = TRUE; break; default: break; } } } /*****************************************************************************/ static void Redraw(void) { XEvent dummy; while (XCheckTypedWindowEvent(display, main_window, Expose, &dummy)) ; XCopyArea(display, all_pm, main_window, gc, 0, 0, SIZE, SIZE, 0, 0); } /*****************************************************************************/ static Pixel GetColor(char *name) { XColor color; XWindowAttributes attributes; XGetWindowAttributes(display, root, &attributes); color.pixel = 0; if (!XParseColor(display, attributes.colormap, name, &color)) { fprintf(stderr, "ERR: can't parse color ``%s''.\n", name); } else if (!XAllocColor(display, attributes.colormap, &color)) { fprintf(stderr, "ERR: can't allocate ``%s''.\n", name); } return color.pixel; } /****************************************************************************** ******************************************************************************* END OF FILE ******************************************************************************* ******************************************************************************/