// // Temperature.app // // Copyright (c) 2000-2002 Per Liden // // 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, // USA. // #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Xpm.h" #include "Temperature.h" #include "pixmaps/main.xpm" #include "pixmaps/redlight.xpm" volatile static ChildStatus childStatus; static void catchBrokenPipe(int sig) { exit(0); } static void catchChildExit(int sig) { int status; waitpid(-1, &status, 0); if (WIFEXITED(status)) { if (WEXITSTATUS(status)) { childStatus = ChildError; } else { childStatus = ChildDone; } } else { childStatus = ChildError; } if (childStatus == ChildError) { std::cerr << APPNAME << ": could not fetch temperature (wget failed), try option -V for more information" << std::endl; } } Temperature::Temperature(int argc, char** argv) { XClassHint classHint; XSizeHints sizeHints; XWMHints wmHints; Atom deleteWindow; Xpm* image; char* displayName = NULL; mInstanceName = INSTANCENAME; mStationId = 0; mTemperature[0] = 0; mTime[0] = 0; mTimeDiff = 0.0; mFahrenheit = false; mShowTime = false; mTime12HourFormat = false; mVerbose = false; // Parse command line if (argc>1) { for (int i=1; i" << std::endl; tryHelp(argv[0]); exit(0); } // Open display if ((mDisplay = XOpenDisplay(displayName)) == NULL) { std::cerr << APPNAME << ": could not open display " << displayName << std::endl; exit(0); } // Get root window mRoot = RootWindow(mDisplay, DefaultScreen(mDisplay)); // Create windows mAppWin = XCreateSimpleWindow(mDisplay, mRoot, 1, 1, 64, 64, 0, 0, 0); mIconWin = XCreateSimpleWindow(mDisplay, mAppWin, 0, 0, 64, 64, 0, 0, 0); // Set classhint classHint.res_name = mInstanceName; classHint.res_class = CLASSNAME; XSetClassHint(mDisplay, mAppWin, &classHint); // Create delete atom deleteWindow = XInternAtom(mDisplay, "WM_DELETE_WINDOW", False); XSetWMProtocols(mDisplay, mAppWin, &deleteWindow, 1); XSetWMProtocols(mDisplay, mIconWin, &deleteWindow, 1); // Set windowname XStoreName(mDisplay, mAppWin, APPNAME); XSetIconName(mDisplay, mAppWin, APPNAME); // Set sizehints sizeHints.flags= USPosition; sizeHints.x = 0; sizeHints.y = 0; XSetWMNormalHints(mDisplay, mAppWin, &sizeHints); // Set wmhints wmHints.initial_state = WithdrawnState; wmHints.icon_window = mIconWin; wmHints.icon_x = 0; wmHints.icon_y = 0; wmHints.window_group = mAppWin; wmHints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; XSetWMHints(mDisplay, mAppWin, &wmHints); // Set command XSetCommand(mDisplay, mAppWin, argv, argc); // Set background image image = new Xpm(mDisplay, mRoot, main_xpm); image->setWindowPixmapShaped(mIconWin); delete image; // Create status led mStatusLed = XCreateSimpleWindow(mDisplay, mIconWin, LED_X, LED_Y, 3, 2, 0, 0, 0); image = new Xpm(mDisplay, mRoot, redlight_xpm); image->setWindowPixmap(mStatusLed); delete image; XMapWindow(mDisplay, mIconWin); XMapWindow(mDisplay, mAppWin); XSync(mDisplay, False); // Catch broker pipe signal signal(SIGPIPE, catchBrokenPipe); // Catch child exit signal signal(SIGCHLD, catchChildExit); } void Temperature::tryHelp(char* appname) { std::cerr << std::endl << "Try `" << appname << " --help' for more information" << std::endl; } void Temperature::showHelp() { std::cerr << APPNAME << " Copyright (c) 2000-2002 by Per Liden (per@fukt.bth.se)" << std::endl << std::endl << "options:" << std::endl << " -s set station id (ICAO Location Indicator)" << std::endl << " -t 12|24 display time of temperature observation (12 or 24 hour format)" << std::endl << " -f display degrees in Fahrenheit" << std::endl << " -V display verbose messages from wget" << std::endl << " -n set client instance name" << std::endl << " -d set display" << std::endl << " -v print version and exit" << std::endl << " -h, --help display this help text and exit" << std::endl << std::endl << "You must supply the ICAO Location Indicator (a 4-character string)" << std::endl << "of a weather station near you. You can search for a station on" << std::endl << "this site: http://www.nws.noaa.gov/oso/siteloc.shtml" << std::endl; } void Temperature::checkArgument(char** argv, int argc, int index) { if (argc-1 < index+1) { std::cerr << APPNAME << ": option '" << argv[index] << "' requires an argument" << std::endl; tryHelp(argv[0]); exit(0); } } void Temperature::showLed(bool show) { if (show) { XMapWindow(mDisplay, mStatusLed); } else { XUnmapWindow(mDisplay, mStatusLed); } XSync(mDisplay, False); } void Temperature::calcTimeDiff() { struct tm* t; double localTime; double universalTime; time_t currentTime; currentTime = time(0); t = gmtime(¤tTime); universalTime = (double)t->tm_hour + (double)t->tm_min / 60.0 + (double)t->tm_sec / 3600.0; currentTime = time(0); t = localtime(¤tTime); localTime = (double)t->tm_hour + (double)t->tm_min / 60.0 + (double)t->tm_sec / 3600.0; mTimeDiff = universalTime - localTime; if (mTimeDiff > 24.0) { mTimeDiff -= 24.0; } else if (mTimeDiff < 0.0) { mTimeDiff += 24.0; } } void Temperature::setTime(char* utcTime) { char unit[3]; int hour = 0; int min = 0; strncpy(unit, &utcTime[0], 2); hour = atoi(unit); strncpy(unit, &utcTime[2], 2); min = atoi(unit); double time = ((double)hour + (double)min / 60.0) - mTimeDiff; if (time < 0.0) { time += 24.0; } else if (time > 24.0) { time -= 24.0; } hour = (int)time; min = (int)((time - (double)hour) * 60.0 + 0.5); if (min >= 60){ min = 0; if (++hour >= 24) { hour = 0; } } if (mTime12HourFormat) { if (hour >= 0 && hour <= 11) { mTimeAMPM = "AM"; } else { mTimeAMPM = "PM"; } if (hour == 0) { hour = 12; } else if (hour > 12) { hour -= 12; } } sprintf(mTime, "%d:%.2d", hour, min); } bool Temperature::updateTemperture(ifstream& file) { const int MAX_LINE = 1024; char buffer[MAX_LINE]; if (mShowTime) { // Find time of observation char* start; char time[5]; file.getline(buffer, MAX_LINE - 1); file.getline(buffer, MAX_LINE - 1); if ((start = strstr(buffer, "UTC")) == 0) { return false; } strncpy(time, start - 5, 4); setTime(time); } // Find temperature while (!file.eof()) { file >> buffer; if (!strcmp(buffer, "Temperature:")) { file >> buffer; if (buffer && strlen(buffer) < 5) { char* unit; if (mFahrenheit) { strcpy(mTemperature, buffer); unit = " °F"; } else { sprintf(mTemperature, "%d", (int)rint((atoi(buffer) - 32) / 1.8)); unit = " °C"; } Xpm* image = new Xpm(mDisplay, mRoot, main_xpm); if (mShowTime) { if (mTime12HourFormat) { image->drawComposedString(TIME_POS, TIME_FONT, mTime, AMPM_FONT, mTimeAMPM); } else { image->drawString(TIME_POS, TIME_FONT, mTime); } image->drawComposedString(TEMP_WITH_TIME_POS, TEMP_FONT, mTemperature, UNIT_FONT, unit); } else { image->drawComposedString(TEMP_POS, TEMP_FONT, mTemperature, UNIT_FONT, unit); } image->setWindowPixmap(mIconWin); delete image; XSync(mDisplay, False); return true; } } } std::cerr << APPNAME << ": could not fetch temperature (unknown file format)" << std::endl; return false; } void Temperature::run() { if (mShowTime) { calcTimeDiff(); } int counter = 0; while(1) { if (counter <= 0) { char tmpFile[sizeof(TMP_FILE)] = TMP_FILE; int fd = mkstemp(tmpFile); if (fd == -1) { std::cerr << APPNAME << ": could not create temporary file " << tmpFile << ": " << strerror(errno) << std::endl; exit(1); } close(fd); counter = UPDATE_INTERVAL; childStatus = ChildRunning; signal(SIGCHLD, catchChildExit); showLed(true); int pid = fork(); if (pid == 0) { const char* verbose = (mVerbose ? "--verbose" : "--quiet"); char* URL = new char[strlen(METAR_URL) + strlen(mStationId) + 1]; sprintf(URL, METAR_URL, mStationId); execlp("wget", "wget", "--cache=off", "--tries=0", verbose, "-O", tmpFile, URL, 0); std::cerr << APPNAME << ": could not fetch temperature (wget not found in $PATH)" << std::endl; remove(tmpFile); exit(0); } else if (pid == -1) { std::cerr << APPNAME << ": could not fetch temperature (fork() failed)" << std::endl; } else { bool toggle = true; while (childStatus == ChildRunning) { showLed(toggle); toggle ^= true; sleep(1); } showLed(true); if (childStatus == ChildDone) { ifstream file(tmpFile); if (file) { if (updateTemperture(file)) { showLed(false); } file.close(); } } remove(tmpFile); } } else { counter--; sleep(1); XSync(mDisplay, False); } } }