/******************************************************************************** * File: wdgo.cpp * * Version: 0.3 * * Date: 20080508 * * Author: Gaspar Fernández (helyo@totaki.com) * * * * Copyright (C) 2008 Gaspar Fernández * * * * 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 3 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, see . * * * ******************************************************************************** * Description: * It is a Window Maker dockapp wich fetches weather information of the * selected cities from National Weather Service (http://weather.noaa.gov/) * to display current temperature and chage background image depending on * the current weather conditions. * * Change History: * Date (D.M.Y) Author Modification * 08.05.2008 Gaspar Fernández Initial release * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "XDraw.h" #include "errors.h" #include "localtemp.h" #include "dwgo.h" #include "strutils.cpp" #include "config.h" using namespace std; typedef struct { vector weathers; bool loaded; int refresh; // When timer reaches refresh it reloads the information int counter; // Timer } Wth_vector; typedef struct { char station[5]; // Metar ID [ 4 characters + \0 char name[16]; // Station name (it's for you). It's short to fit in. } T_Station; typedef struct { int x, y, z; } T_Point; typedef struct { char *img; // Xpm asociated char *text_font; // Location text font char *temp_font; // Temperature text font char *time_font; // Temperature text font XDraw::XDrawColor text_color; // Text color XDraw::XDrawColor temp_color; // Temperature Color XDraw::XDrawColor time_color; // Temperature Color T_Point stname; // Where to put the station name T_Point sttemp; // Where to put the temperature T_Point sttime; // Where to put the temperature } T_Theme; typedef struct { int x1, x2, y1, y2; XDraw::XDrawColor in_color, out_color, bar_color; } T_WaitBox; typedef struct { vector stations; // List of preferred stations T_Theme metar_themes[TOTAL_THEMES]; // Load themes preferences T_WaitBox wbox; // Wait box int update_int; // Update interval char deg_unit; // Celsius or Fahrenheit } DwgoConf; /************************************************************* * Function: fetchWeatherInfo * ************************************************************* * Description: * * Fetch weather information from the server. It * * downloads a file for every location in our vector. * * * * Input: * * Wth_vector *weathers - Our weather vector * * * * Output: * * Nothing * * * * Change History: * * Date Author Modification * * 20101106 Gaspar Fernández Added error status * *************************************************************/ void fetchWeatherInfo(Wth_vector *weathers) { Wth_vector *wths= (Wth_vector *)weathers; // bool allok=true; for (unsigned int k=0; kweathers.size(); k++) { localtemp *current = wths->weathers.at(k); wths->loaded=false; // This will make animated bar disappear when loaded if (!current->getInfo()) { verbsth(VERB_WARNING, "Don't have access to the server... I'll try later"); break; } else if (current->error) { verbsth(VERB_WARNING, "Got an error while retrieving information."); break; } } // wths->loaded=allok; // All loaded } /************************************************************* * Function: getWeatherInfo * ************************************************************* * Description: * * Calls fetchWeatherInfo periodically * * * * Input: * * voir *weathers - Our weather vector. It's a void type * * because it is called using pthread_create. * * * * Output: * * NULL * * * * Change History: * * Date Author Modification * * * *************************************************************/ void *getWeatherInfo(void *weathers) { while (1) // Fetch periodically temperatures { if (((Wth_vector *)weathers)->counter>=((Wth_vector *)weathers)->refresh) { ((Wth_vector *)weathers)->counter=0; fetchWeatherInfo((Wth_vector *)weathers); } sleep(1); // fetchWeatherInfo((Wth_vector *)weathers); ((Wth_vector *)weathers)->counter++; } return NULL; } /************************************************************* * Function: load_coords * ************************************************************* * Description: * * Translates a string with a,b,c with a,b,c three ints * * to a T_Point structure. But the string may contain two, * * or one number. It is used to locate text, so X * * coordinate, can wi CENTER_TEXT, and Z can be * * DEFAULT_MAX_WIDTH * * * * Input: * * a string with the coordinates separated with commas. * * * * Output: * * T_Point structure containing x, y and z * * * * Change History: * * Date Author Modification * * * *************************************************************/ T_Point load_coords(const string &str) { T_Point coord; size_t coma = str.find(',',0); // Finds comma size_t coma2 = str.find(',', coma+1); // Finds another comma coord.z = DEFAULT_MAX_WIDTH; if (coma!=string::npos) { // Load coordinates coord.x = atoi(trim(str.substr(0,coma)).data()); if (coma2!=string::npos) { coord.z = atoi(trim(str.substr(coma+1, coma2-coma+1)).data()); coord.y = atoi(trim(str.substr(coma2+1)).data()); } else coord.y = atoi(trim(str.substr(coma+1)).data()); } else { // Centers text in X coord.x = CENTER_TEXT; coord.y = atoi(str.data()); } return coord; } /************************************************************* * Function: load_colors * ************************************************************* * Description: * * Read the string containing red, green and blue values * * for the desired colour separated with commas. And stores * * this values in a XDrawColor structure * * * * Input: * * string with r,g,b values * * * * * Output: * * XDrawColor structure with that information * * * * Change History: * * Date Author Modification * * * *************************************************************/ XDraw::XDrawColor load_colors(string str) { XDraw::XDrawColor color; sscanf(str.data(),"%d %d %d", &color.r, &color.g, &color.b); return color; } /************************************************************* * Function: load_wbcoords * ************************************************************* * Description: * * Made only to read from config. file the coords of the * * upper left and lower right corners of the wait box * * (this one that appears when the data is being downloaded)* * * * Input: * * string with the coords. separated with spaces * * T_WaitBox structure where to store the data * * * * Output: * * inside T_WaitBox structure, the coordinates of the * * box are loaded from the string * * * * Change History: * * Date Author Modification * * * *************************************************************/ void load_wbcoords(string str, T_WaitBox *wbox) { sscanf(str.data(),"%d %d %d %d", &wbox->x1, &wbox->y1, &wbox->x2, &wbox->y2); } bool existsfilepath(const char* path, const char* file, char pathfile[]) { bzero(pathfile, 256); // Erase last data strcpy(pathfile, path); strcat((char*)pathfile, file); return (file_exists(pathfile)); } /************************************************************* * Function: load_config * ************************************************************* * Description: * * Loads the config file into the DwgoConf structure. * * We also do some checks to return error codes. * * * * Input: * * char* file - File to read the configuration * * DwgoConf &config - Where to put the configuration * * Display *display - Used to make some checks * * * * Output: * * DwgoConf &config - We store here the configuration * * * * Change History: * * Date Author Modification * * * *************************************************************/ void load_config(const char *file, DwgoConf &config, Display *disp, const char *homedir) { ifstream inFile; string temp,a,b,c,tmp; char *other_dir; char *datadir; size_t pos, pos2; T_Station station; int aux; char pathfile[256]; // 256 temp chars for path+file // This array stores all themes, as we may read it in the file. const char *theme_keywords[TOTAL_THEMES]={"default", "clear", "cloudy", "broken", "tcu", "rainy", "snowy", "hail", "foggy", "dust", "otparts"}; cout<"); // An arrow indicates theme or waitbox properties if (pos2!=string::npos) { c=a.substr(pos2+2); // Store here what's after the -> a=a.substr(0,pos2); // Store here what's between the = and the -> aux=find_str_in_array(a.data(),theme_keywords, TOTAL_THEMES); // if we've found a, in the array of themes... if (aux>-1) // Right theme, let's see the options { if (c=="img") // img property, specify the XPM to load when this theme is active { tmp="/"+b; if (file_exists(b.data())) load_str_chr(&config.metar_themes[aux].img, b); else if (existsfilepath(other_dir, tmp.data(), pathfile)) load_str_chr(&config.metar_themes[aux].img, pathfile); else if (existsfilepath(datadir, tmp.data(), pathfile)) load_str_chr(&config.metar_themes[aux].img, pathfile); else verbsth(VERB_WARNING,"Can't find default img file: "+b+" for "+c+"_img attribute"); } else if (c=="txtfont") // text found - Generally station name { if (testfont(b.data(), disp)) load_str_chr(&config.metar_themes[aux].text_font, b); else { if (aux>0) { load_str_chr(&config.metar_themes[aux].text_font, config.metar_themes[0].text_font); // Load default font verbsth(VERB_WARNING, ("Can't load font: ")+b+(" loading default instead.")); } else error_handler(ERR_BADFONT, (char*) b.data()); // Can't continue } } else if (c=="tempfont") // temperature font { if (testfont(b.data(), disp)) load_str_chr(&config.metar_themes[aux].temp_font, b); else { if (aux>0) { load_str_chr(&config.metar_themes[aux].temp_font, config.metar_themes[0].temp_font); // Load default font verbsth(VERB_WARNING, ("Can't load font: ")+b+(" loading default instead.")); } else error_handler(ERR_BADFONT, (char*) b.data()); // Can't continue } } else if (c=="timefont") // time fond - Specify when was the data taken { if (testfont(b.data(), disp)) load_str_chr(&config.metar_themes[aux].time_font, b); else { if (aux>0) { load_str_chr(&config.metar_themes[aux].time_font, config.metar_themes[0].time_font); // Load default font verbsth(VERB_WARNING, ("Can't load font: ")+b+(" loading default instead.")); } else error_handler(ERR_BADFONT, (char*) b.data()); // Can't continue } } else if (c=="txtloc") // Where to put the station name text config.metar_themes[aux].stname=load_coords(b); else if (c=="timloc") // Where to put the time text config.metar_themes[aux].sttime=load_coords(b); else if (c=="tmploc") // Where to put the temperature text config.metar_themes[aux].sttemp=load_coords(b); else if (c=="textcolor") // Station name text color config.metar_themes[aux].text_color=load_colors(b); else if (c=="timecolor") // Time text color config.metar_themes[aux].time_color=load_colors(b); else if (c=="tempcolor") // Temperature textcolor config.metar_themes[aux].temp_color=load_colors(b); } else if (a=="waitbox") // If it is not a theme, it may be the waitbox { if (c=="coords") // Coordinates load_wbcoords(b, &config.wbox); else if (c=="out_color") // Border color config.wbox.out_color=load_colors(b); else if (c=="in_color") // Fill in color config.wbox.in_color=load_colors(b); else if (c=="bar_color") // Moving bar color config.wbox.bar_color=load_colors(b); } else verbsth(VERB_WARNING, "Sorry, I can't recognise "+a+"_"+c+" attribute."); } else if (a=="update_interval") // Weather will update each (update_interval) seconds config.update_int=atoi(b.data()); else if (a=="deg_unit") // (C)elsius or (F)ahrenheit config.deg_unit=b[0]; // Only first char break; case ' ': // If the first thing we see is a " ", insead of a "=" if (a== "AddStation") // Adds station to monitor { pos=b.find(":",0); // The stations must be specified with the station name, separated with ":" a=b.substr(0,pos); b=b.substr(pos+1); strcpy(station.station,a.data()); strcpy(station.name,b.substr(0,14).data()); // Just 15 characters config.stations.push_back(station); verbsth(VERB_NOTICE, "Add Station \""+a+"\" called \""+b+"\""); } break; } } } inFile.close(); if (config.update_int==0) // Prevent update_interval from being zero config.update_int=DEFAULT_UPDATE_INTERVAL; // If it is not defined, or 0, replace it with the default value if (config.metar_themes[DEFAULT_THEME].sttemp.y==-1) // Temperature must be shown error_handler(ERR_BADSTTEMP,NULL); // Colors must have positive values if (config.metar_themes[DEFAULT_THEME].text_color.r==-1) error_handler(ERR_BADDFTCLR,NULL); if (config.metar_themes[DEFAULT_THEME].time_color.r==-1) error_handler(ERR_BADDFICLR,NULL); if (config.metar_themes[DEFAULT_THEME].temp_color.r==-1) error_handler(ERR_BADDFECLR,NULL); } else error_handler(ERR_CFGNOTFOUND,NULL); } /************************************************************* * Function: time_diff * ************************************************************* * Description: * * Calculates local timezone time difference with GMT. * * * * Input: * * Nothing * * * * Output: * * int - Time difference in seconds (local_time-gmt_time)* * * * Change History: * * Date Author Modification * * * *************************************************************/ int time_diff () { struct tm *local, *gmt; int local_s, gmt_s; time_t tmp; tmp = time(0); gmt = gmtime(&tmp); if (gmt->tm_yday==0) gmt->tm_yday=366; gmt_s = gmt->tm_yday*86400+gmt->tm_hour*3600 + gmt->tm_min* 60 + gmt->tm_sec; tmp = time(0); local = localtime(&tmp); if (local->tm_yday==0) local->tm_yday=366; local_s = local->tm_yday*86400 + local->tm_hour*3600 + local->tm_min*60 + local->tm_sec; return (local_s-gmt_s); } /************************************************************* * Function: displaytemp * ************************************************************* * Description: * * Draws an image inside the dockapp and renders text * * with location name, temperature and time when the data * * was taken. * * * * Input: * * XDraw *image - Image which will be drawn in the * * dockapp. * * DwgoConf cfg - Configuration * * localtemp local_stt - Local Station information * * int tm_diff - Time difference (see time_diff() func.)* * char *xpmthemes - XPM images to display * * * * Output: * * Nothing * * * * Change History: * * Date Author Modification * * * *************************************************************/ void displaytemp(XDraw *image, const DwgoConf cfg, localtemp *local_stt, int tm_diff, char *xpm_themes[]) { char tmp_disp[10]; // Aux to display temperature char *txt_font; char *tmp_font; char *tim_font; int theme=local_stt->theme; XDraw::XDrawColor txcolor, ticolor, tecolor; T_Point sttemp, sttext, sttime; time_t time_taking; struct tm *moment; // We load each xpm_themes image when it is needed. if (xpm_themes[theme]==NULL) { if (file_exists(cfg.metar_themes[theme].img)) { XpmReadFileToBuffer(cfg.metar_themes[theme].img, &xpm_themes[theme]); verbsth(VERB_NOTICE, (string)"Loading img. theme: "+cfg.metar_themes[theme].img); } else { // If xpm file doesn't exists we load the default theme local_stt->theme=DEFAULT_THEME; theme=DEFAULT_THEME; } } // We do some checks and we change theme details to default details when we can't use them. // We copy this data to our temp string. If we are quick, themes can change and the app crash if (cfg.metar_themes[theme].text_font!=NULL) load_str_chr(&txt_font,cfg.metar_themes[theme].text_font); else load_str_chr(&txt_font,cfg.metar_themes[0].text_font); if (cfg.metar_themes[theme].temp_font!=NULL) load_str_chr(&tmp_font,cfg.metar_themes[theme].temp_font); else load_str_chr(&tmp_font,cfg.metar_themes[0].temp_font); if (cfg.metar_themes[theme].time_font!=NULL) load_str_chr(&tim_font,cfg.metar_themes[theme].time_font); else load_str_chr(&tim_font,cfg.metar_themes[0].time_font); // (C)elsius of (F)ahrenheit if (cfg.deg_unit=='F') sprintf(tmp_disp, "%d "DEG_SYMBOL"F", local_stt->fahrenheit); else sprintf(tmp_disp, "%d "DEG_SYMBOL"C", local_stt->celsius); image->replace_background(xpm_themes[theme]); // Load the background image image->setWindowPixmapShaped(); // If y position of the text is -1 in the current theme, it will be replaced with default theme position. // but the temperature. It will be if y<=-1 (if text or time y position is >-1 it won't be displayed) sttemp=(cfg.metar_themes[theme].sttemp.y>-1)?cfg.metar_themes[theme].sttemp:cfg.metar_themes[0].sttemp; sttext=(cfg.metar_themes[theme].stname.y==-1)?cfg.metar_themes[DEFAULT_THEME].stname:cfg.metar_themes[theme].stname; sttime=(cfg.metar_themes[theme].sttime.y==-1)?cfg.metar_themes[DEFAULT_THEME].sttime:cfg.metar_themes[theme].sttime; // Test current theme color // If red value of the color is -1, the color will be replaced with the default. txcolor=(cfg.metar_themes[theme].text_color.r==-1)?cfg.metar_themes[DEFAULT_THEME].text_color:cfg.metar_themes[theme].text_color; ticolor=(cfg.metar_themes[theme].time_color.r==-1)?cfg.metar_themes[DEFAULT_THEME].time_color:cfg.metar_themes[theme].time_color; tecolor=(cfg.metar_themes[theme].temp_color.r==-1)?cfg.metar_themes[DEFAULT_THEME].temp_color:cfg.metar_themes[theme].temp_color; // Draw strings image->drawString(sttemp.x, sttemp.y, sttemp.z, tecolor, (char*)tmp_font, tmp_disp); if (sttext.y>-1) image->drawString(sttext.x, sttext.y, sttext.z, txcolor, (char*)txt_font, (char*)local_stt->location_name.data()); if ((sttime.y>-1) && (local_stt->loaded)) { time_taking=local_stt->info_time+tm_diff; // Translates to local time moment=localtime(&time_taking); sprintf(tmp_disp, "%.2d:%.2d", moment->tm_hour,moment->tm_min); // Makes it 00:00 image->drawString(sttime.x, sttime.y, sttime.z, ticolor, (char*)tim_font, (char*)tmp_disp); } image->Sync(); } /************************************************************* * Function: config_defaults * ************************************************************* * Description: * * Loads the default configuration in DwgoConf structure.* * * * * * Input: * * DwgoConf *Dwgo_Configuration * * * * Output: * * DwgoConf *Dwgo_Configuration - It will have defaults * * * * Change History: * * Date Author Modification * * * *************************************************************/ void config_defaults(DwgoConf *Dwgo_Configuration) { const T_Point def_sttemp = DEFAULT_STTEMP; const XDraw::XDrawColor clnull = DEFAULT_STTEMP; Dwgo_Configuration->wbox.x1=2; Dwgo_Configuration->wbox.x2=62; Dwgo_Configuration->wbox.y1=2; Dwgo_Configuration->wbox.y1=12; Dwgo_Configuration->wbox.in_color=setDrawColor(100,100,20); Dwgo_Configuration->wbox.out_color=setDrawColor(10,10,2); Dwgo_Configuration->wbox.bar_color=setDrawColor(50,50,12); for (int j=0;jmetar_themes[j].text_font=NULL; Dwgo_Configuration->metar_themes[j].temp_font=NULL; Dwgo_Configuration->metar_themes[j].time_font=NULL; Dwgo_Configuration->metar_themes[j].sttemp=def_sttemp; Dwgo_Configuration->metar_themes[j].stname=def_sttemp; Dwgo_Configuration->metar_themes[j].sttime=def_sttemp; Dwgo_Configuration->metar_themes[j].text_color=clnull; Dwgo_Configuration->metar_themes[j].temp_color=clnull; Dwgo_Configuration->metar_themes[j].time_color=clnull; } } /************************************************************* * Function: weathers_create_list * ************************************************************* * Description: * * Fills the Wth_vector weathers vector with the * * stations loaded from the confiuration file. And flag * * the structure to update. * * * * Input: * * Wth_vector *weathers - * * DwgoConf Dwgo_Configuration - Where to get the data from* * * * Output: * * Wth_vector - We will fill in the weathers vector here. * * * * Change History: * * Date Author Modification * * * *************************************************************/ void weathers_create_list(Wth_vector *weathers, DwgoConf Dwgo_Configuration) { weathers->counter=Dwgo_Configuration.update_int; // Refresh now !! weathers->refresh=Dwgo_Configuration.update_int; // Refresh now !! weathers->loaded=false; weathers->weathers.clear(); for (unsigned int k=0; kweathers.push_back(new localtemp((char*)Dwgo_Configuration.stations.at(k).station, (char*)Dwgo_Configuration.stations.at(k).name)); } /************************************************************* * Function: weathers_loader * ************************************************************* * Description: * * Calls weathers_create_list and creates the thread * * that will periodically reload weather information from * * the server * * * * Input: * * Wth_vector - Where the weather info will be stored * * DwgoConf Dwgo_Configuration - Configuration loaded from * * file * * * * Output: * * Nothing * * * * Change History: * * Date Author Modification * * * *************************************************************/ void weathers_loader(Wth_vector *weathers, DwgoConf Dwgo_Configuration) { Wth_vector *th_parm; pthread_t *threads; pthread_attr_t pthread_custom_attr; weathers_create_list(weathers, Dwgo_Configuration); threads=(pthread_t *)malloc(1*sizeof(*threads)); pthread_attr_init(&pthread_custom_attr); th_parm=weathers; pthread_create(threads, &pthread_custom_attr, getWeatherInfo, (void *)(th_parm)); } /************************************************************* * Function: getHomeDir * ************************************************************* * Description: * * Try to guess home directory. First searching HOME * * environment variable, then try getpwuid. * * * * Input: * * Nothing * * * * Output: * * char* path to user home * * * * Change History: * * Date Author Modification * * * *************************************************************/ char *getHomeDir() { static char *home = NULL; if (!home) { home = getenv("HOME") ; } if (!home) { struct passwd *pw = getpwuid(getuid()); if (pw) home = pw->pw_dir ; } return home; } bool copyfile(const char* filefrom, const char* fileto) { FILE *ffrom = NULL; FILE *fto = NULL; char buf[512]; ffrom = fopen( filefrom, "rb" ); if( ffrom != NULL ) { fto = fopen( fileto, "wb" ); if( fto != NULL ) { while (fgets(buf, 256, ffrom)) { if (fputs(buf, fto) == EOF) { // error writing data return false; } } } else return false; fclose( ffrom ); } else return false; return true; } char *locateConfig(const char* homeuser) { static char cfgpath[256]; char tmp[256]; if (existsfilepath(homeuser, "/.dwgo.conf", cfgpath)) return cfgpath; else if (existsfilepath(homeuser, "/.dwgo/dwgo.conf", cfgpath)) return cfgpath; else if (existsfilepath(DATADIR, "/dwgo/dwgo.conf", cfgpath)) { existsfilepath(homeuser, "/.dwgo.conf", tmp); if (copyfile(cfgpath, tmp)) // Copies /usr/share/dwgo/dwgo.conf -> ~/.dwgo.conf strcpy(cfgpath, tmp); // If config file is copied -> Return user configuration return cfgpath; } else if (file_exists("dwgo.conf")) return (char*)"dwgo.conf"; else return NULL; } // Main application int main(int argc, char** argv) { Wth_vector weathers; Display* disp; Window mRoot; Window mAppWin; Window mIconWin; char* xpm_themes[TOTAL_THEMES]; // Where to load XPMs bool bar=false; // Toggle the bar beacuse you like it XClassHint classHint; XSizeHints sizeHints; XWMHints wmHints; Atom deleteWindow; XDraw* image; XEvent report; KeySym ksym; DwgoConf Dwgo_Configuration; // Main configuration int eventmask; char *user_homedir; // User home directory char *home_dir; // Copy of user_homedir because we overwrite user_homedir Q&D char *config_path; // Config file with path int anim=0; // Waitbar animation status bool direc=true; // Direction of the waitbar animation int punter=0; // Location being displayed actually int tm_diff=0; // Time differente timespec tmp={0,30000000L}; // Sleep time between X updates user_homedir= getHomeDir(); home_dir=(char*)malloc(strlen(user_homedir)); strcpy(home_dir, user_homedir); config_path=locateConfig(user_homedir); if (config_path==NULL) error_handler(ERR_NOCFGFILE, NULL); if ((disp = XOpenDisplay(NULL)) == NULL) error_handler(ERR_NODISPLAY, NULL); config_defaults(&Dwgo_Configuration); for (int j=0;jsetDefaultWindow(mIconWin); image->setWindowPixmapShaped(mIconWin); XMapWindow(disp, mIconWin); XMapWindow(disp, mAppWin); XSync(disp, False); eventmask= ButtonPressMask | //ButtonReleaseMask | FocusChangeMask | LeaveWindowMask | KeyPressMask | EnterWindowMask; XSelectInput(disp, mIconWin, eventmask ); while (1) // Main loop!! { if (XCheckMaskEvent(disp, eventmask, &report)) { switch (report.type) { case KeyPress: ksym = XLookupKeysym(&(report.xkey), report.xkey.state); switch (ksym) { // case XK_Escape: // exit(0); // break; case XK_F5: if (weathers.counter>3) // Min. time between refreshes weathers.counter=weathers.refresh; // Refresh weathers else verbsth(VERB_WARNING,"You just have updated temperatures!!! Wait a little bit!"); break; case XK_F6: // Reload conf. file, Useful form theme creation and conf. checks punter=0; weathers.counter=0; // Make sure it won't update during reload config_defaults(&Dwgo_Configuration); for (int j=0;jloaded) || (bar)) { image->DrawRect(Dwgo_Configuration.wbox.x1,Dwgo_Configuration.wbox.y1,Dwgo_Configuration.wbox.x2,Dwgo_Configuration.wbox.y2, Dwgo_Configuration.wbox.out_color); image->DrawRect(Dwgo_Configuration.wbox.x1+1,Dwgo_Configuration.wbox.y1+1,Dwgo_Configuration.wbox.x2-2,Dwgo_Configuration.wbox.y2-2, Dwgo_Configuration.wbox.in_color); image->DrawRect(Dwgo_Configuration.wbox.x1+1+anim,Dwgo_Configuration.wbox.y1+1,6,Dwgo_Configuration.wbox.y2-2, Dwgo_Configuration.wbox.bar_color); if (direc) anim++; else anim--; if ((anim==Dwgo_Configuration.wbox.x2-8) || (anim==0)) // Dwgo_Configuration.wbox.x2 -2 -6 (bar width) direc=!direc; image->Sync(); } else if (!weathers.loaded) { weathers.loaded=true; displaytemp(image, Dwgo_Configuration, weathers.weathers.at(punter), tm_diff, xpm_themes); } } nanosleep(&tmp, NULL); } delete image; }