wmcore: set DESTDIR so binary installs correctly.
[dockapps.git] / pclock / src / Graphics.c
blob4c0aac48e1923e988f414946fbe3f577b2596b18
1 /* -*- Mode: C; fill-column: 79 -*- *******************************************
2 *******************************************************************************
3 pclock -- a simple analog clock program for the X Window System
4 Copyright (C) 1998 Alexander Kourakos
5 Time-stamp: <1998-05-28 21:27:58 awk@oxygene.vnet.net>
7 This program is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free Software
9 Foundation; either version 2 of the License, or (at your option) any later
10 version.
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along with
17 this program; if not, write to the Free Software Foundation, Inc.,
18 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 Author: Alexander Kourakos
21 Email: Alexander@Kourakos.com
22 Web: http://www.kourakos.com/~awk/pclock/
23 *******************************************************************************
24 ******************************************************************************/
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <time.h>
29 #include <math.h>
31 #include <X11/Xlib.h>
32 #include <X11/Xutil.h>
33 #include <X11/xpm.h>
34 #include <X11/extensions/shape.h>
36 #include "PClock.h"
38 /*****************************************************************************/
41 * The name of the XPM should be ``clock_background''.
44 #include "Default.xpm"
46 /*****************************************************************************/
48 static Display *display;
49 static Window root, window, icon_window, main_window;
50 static GC gc;
51 static Atom wm_delete_window;
52 static Pixel back_pixel, hand_pixel, second_hand_pixel;
53 static Pixmap back_pm, mask_pm, all_pm;
54 static int old_hour = 0, old_minute = 0, old_second = 0;
56 /*****************************************************************************/
58 static Pixel GetColor(char *);
59 static void Redraw(void);
61 /*****************************************************************************/
63 void
64 CreateWindow(int ac, char *av[])
66 int zero = 0;
67 char *app_name = NAME;
68 char *app_class = CLASS;
69 int screen;
70 XSizeHints size_hints;
71 XWMHints wm_hints;
72 XClassHint class_hints;
73 XTextProperty window_name;
74 XGCValues gcv;
75 unsigned long gcm;
76 int result, use_internal_pixmap;
78 size_hints.flags = PMinSize | PMaxSize | PPosition;
79 size_hints.min_width = size_hints.max_width =
80 size_hints.min_height = size_hints.max_height = SIZE;
82 display = XOpenDisplay(NULL);
83 if (display == NULL) {
84 fprintf(stderr, "ERR: could not open display ``%s''..Exiting.\n",
85 XDisplayName(NULL));
86 exit(EXIT_FAILURE);
88 wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", FALSE);
89 screen = DefaultScreen(display);
90 root = RootWindow(display, screen);
92 back_pixel = GetColor("black");
93 hand_pixel = GetColor(option.hand_color);
94 second_hand_pixel = GetColor(option.second_hand_color);
96 use_internal_pixmap = TRUE;
98 if (option.background_pixmap[0] != '\0') {
99 XpmAttributes attributes;
101 attributes.valuemask = XpmSize;
102 result = XpmReadFileToPixmap(display, root, option.background_pixmap,
103 &back_pm, &mask_pm, &attributes);
105 if (result != XpmSuccess)
106 fprintf(stderr, "ERR: trouble loading pixmap\n");
107 else if (attributes.width != SIZE || attributes.height != SIZE)
108 fprintf(stderr, "ERR: pixmap must be %dx%d\n", SIZE, SIZE);
109 else
110 use_internal_pixmap = FALSE;
113 if (use_internal_pixmap) {
114 result = XpmCreatePixmapFromData(display, root, clock_background,
115 &back_pm, &mask_pm, NULL);
116 if (result != XpmSuccess) {
117 if (result == XpmColorFailed)
118 fprintf(stderr, "ERR: unable to allocate pixmap colors..exiting\n");
119 else
120 fprintf(stderr, "ERR: trouble using built-in pixmap..exiting\n");
121 exit(EXIT_FAILURE);
125 all_pm = XCreatePixmap(display, root, SIZE, SIZE,
126 DefaultDepth(display, screen));
128 XWMGeometry(display, screen, "", NULL, 0, &size_hints, &zero, &zero,
129 &size_hints.width, &size_hints.height, &zero);
131 window = XCreateSimpleWindow(display, root,
132 0, 0, size_hints.width, size_hints.height,
133 0, back_pixel, back_pixel);
135 icon_window = XCreateSimpleWindow(display, root,
136 0, 0, size_hints.width, size_hints.height,
137 0, back_pixel, back_pixel);
139 wm_hints.window_group = window;
140 if (option.under_windowmaker) {
141 wm_hints.initial_state = WithdrawnState;
142 wm_hints.icon_window = icon_window;
143 wm_hints.icon_x = wm_hints.icon_y = 0;
144 wm_hints.flags =
145 StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
146 main_window = icon_window;
147 } else {
148 wm_hints.initial_state = NormalState;
149 wm_hints.flags = StateHint | WindowGroupHint;
150 main_window = window;
153 XSetWMNormalHints(display, window, &size_hints);
154 class_hints.res_name = app_name;
155 class_hints.res_class = app_class;
156 XSetClassHint(display, window, &class_hints);
157 XSetClassHint(display, icon_window, &class_hints);
159 XSelectInput(display, main_window, ExposureMask | StructureNotifyMask);
161 if (XStringListToTextProperty(&app_name, 1, &window_name) == 0) {
162 fprintf(stderr, "ERR: can't allocate window name..exiting\n");
163 exit(EXIT_FAILURE);
165 XSetWMName(display, window, &window_name);
167 gcm = GCForeground | GCBackground | GCGraphicsExposures;
168 gcv.foreground = hand_pixel;
169 gcv.background = back_pixel;
170 gcv.graphics_exposures = 0;
171 gc = XCreateGC(display, root, gcm, &gcv);
173 XSetWMHints(display, window, &wm_hints);
174 XStoreName(display, window, app_name);
175 XSetIconName(display, window, app_name);
176 XSetCommand(display, window, av, ac);
177 XSetWMProtocols(display, main_window, &wm_delete_window, 1);
178 XSetWindowBackgroundPixmap(display, main_window, back_pm);
179 XShapeCombineMask(display, main_window, ShapeBounding, 0, 0,
180 mask_pm, ShapeSet);
181 XMapWindow(display, window);
184 /*****************************************************************************/
186 void
187 DestroyWindow(void)
189 XFreeGC(display, gc);
190 XFreePixmap(display, all_pm);
191 XFreePixmap(display, back_pm);
192 XFreePixmap(display, mask_pm);
193 XDestroyWindow(display, window);
194 XDestroyWindow(display, icon_window);
195 XCloseDisplay(display);
198 /*****************************************************************************/
200 void
201 UpdateClock(void)
203 int h = old_hour, m = old_minute, s;
204 struct tm *time_struct;
205 time_t curtime;
206 double angle;
207 int hx, hy, mx, my, sx, sy;
209 curtime = time(NULL);
210 time_struct = localtime(&curtime);
212 h = time_struct->tm_hour;
213 m = time_struct->tm_min;
214 s = time_struct->tm_sec;
217 * Even if we aren't showing the second hand, redraw anyway so a lost
218 * X connection can be detected relatively quickly.
221 if (h == old_hour && m == old_minute && s == old_second)
222 return;
224 XCopyArea(display, back_pm, all_pm, gc, 0, 0, SIZE, SIZE, 0, 0);
226 angle = (M_PI / 6.0) * (double) h + (M_PI / 360.0) * (double) m;
227 hx = (SIZE / 2) + (int) ((double) option.hour_hand_length * sin(angle));
228 hy = (SIZE / 2) - (int) ((double) option.hour_hand_length * cos(angle));
230 angle = (M_PI / 30.0) * (double) m;
231 mx = (SIZE / 2) + (int) ((double) option.minute_hand_length * sin(angle));
232 my = (SIZE / 2) - (int) ((double) option.minute_hand_length * cos(angle));
234 XSetLineAttributes(display, gc, option.hand_width, LineSolid, CapRound,
235 JoinRound);
236 XDrawLine(display, all_pm, gc, SIZE / 2, SIZE / 2, hx, hy);
237 XDrawLine(display, all_pm, gc, SIZE / 2, SIZE / 2, mx, my);
239 if (option.show_seconds) {
240 angle = (M_PI / 30.0) * (double) s;
241 sx = (SIZE / 2) + (int) ((double) option.second_hand_length * sin(angle));
242 sy = (SIZE / 2) - (int) ((double) option.second_hand_length * cos(angle));
244 XSetForeground(display, gc, second_hand_pixel);
245 XSetLineAttributes(display, gc, option.second_hand_width, LineSolid,
246 CapRound, JoinRound);
247 XDrawLine(display, all_pm, gc, SIZE / 2, SIZE / 2, sx, sy);
248 XSetForeground(display, gc, hand_pixel);
251 Redraw();
253 old_hour = h;
254 old_minute = m;
255 old_second = s;
258 /*****************************************************************************/
260 void
261 HandleEvents(int *should_quit)
263 XEvent event;
265 *should_quit = FALSE;
267 while (XPending(display)) {
268 XNextEvent(display, &event);
269 switch (event.type) {
270 case Expose:
271 if (event.xexpose.count == 0)
272 Redraw();
273 break;
274 case DestroyNotify:
275 *should_quit = TRUE;
276 break;
277 case ClientMessage:
278 if (event.xclient.data.l[0] == wm_delete_window)
279 *should_quit = TRUE;
280 break;
281 default:
282 break;
287 /*****************************************************************************/
289 static void
290 Redraw(void)
292 XEvent dummy;
294 while (XCheckTypedWindowEvent(display, main_window, Expose, &dummy)) ;
295 XCopyArea(display, all_pm, main_window, gc, 0, 0, SIZE, SIZE, 0, 0);
298 /*****************************************************************************/
300 static Pixel
301 GetColor(char *name)
303 XColor color;
304 XWindowAttributes attributes;
306 XGetWindowAttributes(display, root, &attributes);
308 color.pixel = 0;
309 if (!XParseColor(display, attributes.colormap, name, &color)) {
310 fprintf(stderr, "ERR: can't parse color ``%s''.\n", name);
311 } else if (!XAllocColor(display, attributes.colormap, &color)) {
312 fprintf(stderr, "ERR: can't allocate ``%s''.\n", name);
314 return color.pixel;
317 /******************************************************************************
318 *******************************************************************************
319 END OF FILE
320 *******************************************************************************
321 ******************************************************************************/