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
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 ******************************************************************************/
32 #include <X11/Xutil.h>
34 #include <X11/extensions/shape.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
;
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 /*****************************************************************************/
64 CreateWindow(int ac
, char *av
[])
67 char *app_name
= NAME
;
68 char *app_class
= CLASS
;
70 XSizeHints size_hints
;
72 XClassHint class_hints
;
73 XTextProperty window_name
;
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",
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
);
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");
120 fprintf(stderr
, "ERR: trouble using built-in pixmap..exiting\n");
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;
145 StateHint
| IconWindowHint
| IconPositionHint
| WindowGroupHint
;
146 main_window
= icon_window
;
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");
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,
181 XMapWindow(display
, window
);
184 /*****************************************************************************/
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 /*****************************************************************************/
203 int h
= old_hour
, m
= old_minute
, s
;
204 struct tm
*time_struct
;
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
)
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
,
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
);
258 /*****************************************************************************/
261 HandleEvents(int *should_quit
)
265 *should_quit
= FALSE
;
267 while (XPending(display
)) {
268 XNextEvent(display
, &event
);
269 switch (event
.type
) {
271 if (event
.xexpose
.count
== 0)
278 if (event
.xclient
.data
.l
[0] == wm_delete_window
)
287 /*****************************************************************************/
294 while (XCheckTypedWindowEvent(display
, main_window
, Expose
, &dummy
)) ;
295 XCopyArea(display
, all_pm
, main_window
, gc
, 0, 0, SIZE
, SIZE
, 0, 0);
298 /*****************************************************************************/
304 XWindowAttributes attributes
;
306 XGetWindowAttributes(display
, root
, &attributes
);
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
);
317 /******************************************************************************
318 *******************************************************************************
320 *******************************************************************************
321 ******************************************************************************/