4 // Copyright (c) 2000-2002 Per Liden
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307,
31 #include <sys/types.h>
36 #include "Temperature.h"
38 #include "pixmaps/main.xpm"
39 #include "pixmaps/redlight.xpm"
41 volatile static ChildStatus childStatus
;
43 static void catchBrokenPipe(int sig
)
48 static void catchChildExit(int sig
)
51 waitpid(-1, &status
, 0);
53 if (WIFEXITED(status
)) {
54 if (WEXITSTATUS(status
)) {
55 childStatus
= ChildError
;
57 childStatus
= ChildDone
;
60 childStatus
= ChildError
;
63 if (childStatus
== ChildError
) {
64 std::cerr
<< APPNAME
<< ": could not fetch temperature (wget failed), try option -V for more information" << std::endl
;
68 Temperature::Temperature(int argc
, char** argv
)
75 char* displayName
= NULL
;
77 mInstanceName
= INSTANCENAME
;
84 mTime12HourFormat
= false;
89 for (int i
=1; i
<argc
; i
++) {
91 if (!strcmp(argv
[i
], "-d")) {
92 checkArgument(argv
, argc
, i
);
93 displayName
= argv
[i
+1];
98 else if (!strcmp(argv
[i
], "-s")) {
99 checkArgument(argv
, argc
, i
);
100 mStationId
= argv
[i
+1];
105 else if (!strcmp(argv
[i
], "-f")) {
110 else if (!strcmp(argv
[i
], "-t")) {
112 checkArgument(argv
, argc
, i
);
113 if (!strcmp(argv
[i
+1], "12")) {
114 mTime12HourFormat
= true;
115 } else if (strcmp(argv
[i
+1], "24")) {
116 std::cerr
<< APPNAME
<< ": unknown time format, use 12 or 24" << std::endl
;
123 else if (!strcmp(argv
[i
], "-V")) {
128 else if (!strcmp(argv
[i
], "-n")) {
129 checkArgument(argv
, argc
, i
);
130 mInstanceName
= argv
[i
+1];
135 else if (!strcmp(argv
[i
], "-v")) {
136 std::cerr
<< APPNAME
<< " version " << VERSION
<< std::endl
;
141 else if (!strcmp(argv
[i
], "-h") || !strcmp(argv
[i
], "--help")) {
148 std::cerr
<< APPNAME
<< ": invalid option '" << argv
[i
] << "'" << std::endl
;
155 if (mStationId
== 0) {
156 std::cerr
<< APPNAME
<< ": you must supply a station id using -s <id>" << std::endl
;
162 if ((mDisplay
= XOpenDisplay(displayName
)) == NULL
) {
163 std::cerr
<< APPNAME
<< ": could not open display " << displayName
<< std::endl
;
168 mRoot
= RootWindow(mDisplay
, DefaultScreen(mDisplay
));
171 mAppWin
= XCreateSimpleWindow(mDisplay
, mRoot
, 1, 1, 64, 64, 0, 0, 0);
172 mIconWin
= XCreateSimpleWindow(mDisplay
, mAppWin
, 0, 0, 64, 64, 0, 0, 0);
175 classHint
.res_name
= mInstanceName
;
176 classHint
.res_class
= CLASSNAME
;
177 XSetClassHint(mDisplay
, mAppWin
, &classHint
);
179 // Create delete atom
180 deleteWindow
= XInternAtom(mDisplay
, "WM_DELETE_WINDOW", False
);
181 XSetWMProtocols(mDisplay
, mAppWin
, &deleteWindow
, 1);
182 XSetWMProtocols(mDisplay
, mIconWin
, &deleteWindow
, 1);
185 XStoreName(mDisplay
, mAppWin
, APPNAME
);
186 XSetIconName(mDisplay
, mAppWin
, APPNAME
);
189 sizeHints
.flags
= USPosition
;
192 XSetWMNormalHints(mDisplay
, mAppWin
, &sizeHints
);
195 wmHints
.initial_state
= WithdrawnState
;
196 wmHints
.icon_window
= mIconWin
;
199 wmHints
.window_group
= mAppWin
;
200 wmHints
.flags
= StateHint
| IconWindowHint
| IconPositionHint
| WindowGroupHint
;
201 XSetWMHints(mDisplay
, mAppWin
, &wmHints
);
204 XSetCommand(mDisplay
, mAppWin
, argv
, argc
);
206 // Set background image
207 image
= new Xpm(mDisplay
, mRoot
, main_xpm
);
208 image
->setWindowPixmapShaped(mIconWin
);
212 mStatusLed
= XCreateSimpleWindow(mDisplay
, mIconWin
, LED_X
, LED_Y
, 3, 2, 0, 0, 0);
213 image
= new Xpm(mDisplay
, mRoot
, redlight_xpm
);
214 image
->setWindowPixmap(mStatusLed
);
217 XMapWindow(mDisplay
, mIconWin
);
218 XMapWindow(mDisplay
, mAppWin
);
219 XSync(mDisplay
, False
);
221 // Catch broker pipe signal
222 signal(SIGPIPE
, catchBrokenPipe
);
224 // Catch child exit signal
225 signal(SIGCHLD
, catchChildExit
);
228 void Temperature::tryHelp(char* appname
)
230 std::cerr
<< std::endl
<< "Try `" << appname
<< " --help' for more information" << std::endl
;
233 void Temperature::showHelp()
235 std::cerr
<< APPNAME
<< " Copyright (c) 2000-2002 by Per Liden (per@fukt.bth.se)" << std::endl
<< std::endl
236 << "options:" << std::endl
237 << " -s <id> set station id (ICAO Location Indicator)" << std::endl
238 << " -t 12|24 display time of temperature observation (12 or 24 hour format)" << std::endl
239 << " -f display degrees in Fahrenheit" << std::endl
240 << " -V display verbose messages from wget" << std::endl
241 << " -n <name> set client instance name" << std::endl
242 << " -d <disp> set display" << std::endl
243 << " -v print version and exit" << std::endl
244 << " -h, --help display this help text and exit" << std::endl
246 << "You must supply the ICAO Location Indicator (a 4-character string)" << std::endl
247 << "of a weather station near you. You can search for a station on" << std::endl
248 << "this site: http://www.nws.noaa.gov/oso/siteloc.shtml" << std::endl
;
251 void Temperature::checkArgument(char** argv
, int argc
, int index
)
253 if (argc
-1 < index
+1) {
254 std::cerr
<< APPNAME
<< ": option '" << argv
[index
] << "' requires an argument" << std::endl
;
260 void Temperature::showLed(bool show
)
263 XMapWindow(mDisplay
, mStatusLed
);
265 XUnmapWindow(mDisplay
, mStatusLed
);
267 XSync(mDisplay
, False
);
270 void Temperature::calcTimeDiff()
274 double universalTime
;
277 currentTime
= time(0);
278 t
= gmtime(¤tTime
);
279 universalTime
= (double)t
->tm_hour
+ (double)t
->tm_min
/ 60.0 + (double)t
->tm_sec
/ 3600.0;
281 currentTime
= time(0);
282 t
= localtime(¤tTime
);
283 localTime
= (double)t
->tm_hour
+ (double)t
->tm_min
/ 60.0 + (double)t
->tm_sec
/ 3600.0;
285 mTimeDiff
= universalTime
- localTime
;
286 if (mTimeDiff
> 24.0) {
288 } else if (mTimeDiff
< 0.0) {
293 void Temperature::setTime(char* utcTime
)
299 strncpy(unit
, &utcTime
[0], 2);
301 strncpy(unit
, &utcTime
[2], 2);
304 double time
= ((double)hour
+ (double)min
/ 60.0) - mTimeDiff
;
307 } else if (time
> 24.0) {
312 min
= (int)((time
- (double)hour
) * 60.0 + 0.5);
320 if (mTime12HourFormat
) {
321 if (hour
>= 0 && hour
<= 11) {
329 } else if (hour
> 12) {
333 sprintf(mTime
, "%d:%.2d", hour
, min
);
336 bool Temperature::updateTemperture(ifstream
& file
)
338 const int MAX_LINE
= 1024;
339 char buffer
[MAX_LINE
];
342 // Find time of observation
345 file
.getline(buffer
, MAX_LINE
- 1);
346 file
.getline(buffer
, MAX_LINE
- 1);
347 if ((start
= strstr(buffer
, "UTC")) == 0) {
350 strncpy(time
, start
- 5, 4);
355 while (!file
.eof()) {
357 if (!strcmp(buffer
, "Temperature:")) {
359 if (buffer
&& strlen(buffer
) < 5) {
362 strcpy(mTemperature
, buffer
);
365 sprintf(mTemperature
, "%d", (int)rint((atoi(buffer
) - 32) / 1.8));
369 Xpm
* image
= new Xpm(mDisplay
, mRoot
, main_xpm
);
371 if (mTime12HourFormat
) {
372 image
->drawComposedString(TIME_POS
, TIME_FONT
, mTime
, AMPM_FONT
, mTimeAMPM
);
374 image
->drawString(TIME_POS
, TIME_FONT
, mTime
);
376 image
->drawComposedString(TEMP_WITH_TIME_POS
, TEMP_FONT
, mTemperature
, UNIT_FONT
, unit
);
378 image
->drawComposedString(TEMP_POS
, TEMP_FONT
, mTemperature
, UNIT_FONT
, unit
);
380 image
->setWindowPixmap(mIconWin
);
382 XSync(mDisplay
, False
);
388 std::cerr
<< APPNAME
<< ": could not fetch temperature (unknown file format)" << std::endl
;
392 void Temperature::run()
401 char tmpFile
[sizeof(TMP_FILE
)] = TMP_FILE
;
402 int fd
= mkstemp(tmpFile
);
404 std::cerr
<< APPNAME
<< ": could not create temporary file " << tmpFile
<< ": " << strerror(errno
) << std::endl
;
409 counter
= UPDATE_INTERVAL
;
410 childStatus
= ChildRunning
;
411 signal(SIGCHLD
, catchChildExit
);
415 const char* verbose
= (mVerbose
? "--verbose" : "--quiet");
416 char* URL
= new char[strlen(METAR_URL
) + strlen(mStationId
) + 1];
417 sprintf(URL
, METAR_URL
, mStationId
);
418 execlp("wget", "wget", "--cache=off", "--tries=0", verbose
, "-O", tmpFile
, URL
, 0);
419 std::cerr
<< APPNAME
<< ": could not fetch temperature (wget not found in $PATH)" << std::endl
;
422 } else if (pid
== -1) {
423 std::cerr
<< APPNAME
<< ": could not fetch temperature (fork() failed)" << std::endl
;
426 while (childStatus
== ChildRunning
) {
432 if (childStatus
== ChildDone
) {
433 ifstream
file(tmpFile
);
435 if (updateTemperture(file
)) {
446 XSync(mDisplay
, False
);