dockapps/wmweather+/radar.c
2014-10-05 19:18:49 +01:00

267 lines
6.8 KiB
C

#include "config.h"
/* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
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 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/stat.h>
#include <wraster.h>
#include <X11/xpm.h>
#include "wmweather+.h"
#include "wmgeneral/wmgeneral-x11.h"
#include "wmgeneral/xpm_trans.h"
#include "download.h"
#include "radar.h"
#include "die.h"
/* Important variables */
static time_t radar_time=0;
static char *radar_file=NULL;
static char *radar_newfile=NULL;
static int cropx, cropy, cropw, croph;
static int crossx, crossy;
time_t radar_update_time;
Pixmap radar;
int do_radar_cross;
extern XpmIcon wmgen;
extern GC NormalGC;
extern int screen;
extern int d_depth;
/* prototypes */
static int parse_radar(char *file);
/* functions */
static void reset_radar(Pixmap *r){
XCopyArea(display, wmgen.pixmap, *r, NormalGC, 124, 18, 52, 40, 0, 0);
XCopyArea(display, wmgen.pixmap, *r, NormalGC, 108, 89, 15, 14, 18, 13);
}
static void parse_cross(void){
char *p1, *p2;
if(radar_cross==NULL) return;
crossx=strtol(radar_cross, &p1, 10);
if(crossx<0 || crossx>=52 || p1==NULL || p1==radar_cross || *p1!='x'){
radar_cross=NULL;
return;
}
crossy=strtol(++p1, &p2, 10);
if(crossy<0 || crossy>=40 || (p2!=NULL && *p2!='\0')){
radar_cross=NULL;
return;
}
}
static void parse_crop(void){
char *p1, *p2;
if(radar_crop==NULL) return;
cropx=strtol(radar_crop, &p1, 10);
if(p1==NULL || p1==radar_crop || *p1!='x'){
radar_crop=NULL;
return;
}
cropy=strtol(++p1, &p2, 10);
if(p2==NULL || p2==p1 || *p2!='+'){
radar_crop=NULL;
return;
}
cropw=strtol(p2, &p1, 10);
if(cropw<1 || p1==NULL || *p1!='+'){
radar_crop=NULL;
return;
}
croph=strtol(p1, &p2, 10);
if(croph<1 || (p2!=NULL && *p2!='\0')){
radar_crop=NULL;
return;
}
}
void init_radar(void){
char *e;
radar=XCreatePixmap(display, wmgen.pixmap, 52, 40, d_depth);
reset_radar(&radar);
if(radar_uri==NULL) return;
e=strrchr(radar_uri, '/');
if(e==NULL) e=radar_uri;
else e++;
snprintf(bigbuf, BIGBUF_LEN-21, "%s.", e);
for(e=bigbuf; *e!='\0'; e++){
if(!isalnum(*e) && *e!='.' && *e!='-' && *e!='+' && *e!='%'
&& *e!='?' && *e!='=' && *e!='&') *e='_';
}
strcpy(e, "radar-image");
radar_file=get_pid_filename(bigbuf);
strcpy(e, "new-radar-image");
radar_newfile=get_pid_filename(bigbuf);
radar_update_time=radar_time==0;
parse_crop();
parse_cross();
do_radar_cross=0;
/* Delete stale files, if any */
unlink(radar_file);
unlink(radar_newfile);
}
static void radar_callback(char *filename, void *v){
struct stat statbuf;
if(stat(radar_newfile, &statbuf)>=0){
if(S_ISREG(statbuf.st_mode) && statbuf.st_size!=0
&& parse_radar(radar_newfile)){
rename(radar_newfile, radar_file);
} else {
unlink(radar_newfile);
if(!parse_radar(radar_file)) reset_radar(&radar);
}
}
}
void radar_cleanup(void){
if(radar_file==NULL) return;
unlink(radar_newfile);
unlink(radar_file);
}
void update_radar(int force){
time_t t;
if(radar_file==NULL) return;
t=time(NULL)/60;
if(!force && radar_time>t) return;
radar_time=t+30;
download_file(radar_newfile, radar_uri, radar_post, force?DOWNLOAD_KILL_OTHER_REQUESTS:0, radar_callback, NULL);
}
static RContext *rc=NULL;
static int parse_radar(char *file){
RImage *r, *n;
float w, h;
RColor col={ 0, 0, 0, 255};
int x, y, ww, hh;
errno=0;
radar_update_time=time(NULL);
reset_radar(&radar);
if(rc==NULL){
rc=RCreateContext(display, screen, NULL);
if(rc==NULL){
warn("parse_radar context creation: %s", RMessageForError(RErrorCode));
return 0;
}
}
r=RLoadImage(rc, file, 0);
if(!r) return 0;
if(radar_crop!=NULL){
x=cropx; y=cropy;
ww=cropw; hh=croph;
if(x<0) x+=r->width;
if(y<0) y+=r->height;
if(x<0){ ww+=x; x=0; }
if(y<0){ hh+=y; y=0; }
if(x>=r->width || y>=r->width || ww<=0 || hh<=0){
RReleaseImage(r);
warn("parse_radar radar_crop exceeds image dimensions");
return 0;
}
n=RGetSubImage(r, x, y, ww, hh);
RReleaseImage(r);
r=n;
if(!r){
warn("parse_radar crop: %s", RMessageForError(RErrorCode));
return 0;
}
}
if(r->width>52 || r->height>40 || (r->width!=52 && r->height!=40)){
w=r->width/52;
h=r->height/40;
if(w>h) h=w;
else w=h;
n=RSmoothScaleImage(r, r->width/w, r->height/h);
RReleaseImage(r);
r=n;
if(!r){
warn("parse_radar scale: %s", RMessageForError(RErrorCode));
return 0;
}
}
if(r->width!=52 || r->height!=40){
n=RMakeCenteredImage(r, 52, 40, &col);
RReleaseImage(r);
r=n;
if(!r){
warn("parse_radar center: %s", RMessageForError(RErrorCode));
return 0;
}
}
if(!RConvertImage(rc, r, &radar)){
RReleaseImage(r);
warn("parse_radar convert: %s", RMessageForError(RErrorCode));
return 0;
}
RReleaseImage(r);
return 1;
}
void put_radar(int x, int y, int font){
int i;
XCopyArea(display, radar, wmgen.pixmap, NormalGC, 0, 0, 52, 40, x, y);
if(font==0) i=0;
else i=1;
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 124, 60+i, 54, 1, x-1, y-1);
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 124, 60+i, 54, 1, x-1, y+40);
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 162+i, 64, 1, 40, x-1, y);
XCopyArea(display, wmgen.pixmap, wmgen.pixmap, NormalGC, 162+i, 64, 1, 40, x+52, y);
if(radar_cross && do_radar_cross){
combineWithOpacity(124, 60+i, 52, 1, x, y+crossy, 128);
combineWithOpacity(162+i, 64, 1, 40, x+crossx, y, 128);
}
}