dockapps/pclock/src/Graphics.c

322 lines
10 KiB
C

/* -*- 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 <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#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
*******************************************************************************
******************************************************************************/