3 /* Copyright (C) 2002 Brad Jorsch <anomie@users.sourceforge.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 # if TIME_WITH_SYS_TIME
24 # include <sys/time.h>
28 # include <sys/time.h>
39 #include <sys/types.h>
45 #include "wmgeneral/wmgeneral-x11.h"
46 #include "wmgeneral/mouse_regions.h"
47 #include "wmgeneral/xpm_trans.h"
49 #include "wmweather_master.xpm"
50 static int wmweather_mask_width
;
51 static int wmweather_mask_height
;
52 static char *wmweather_mask_bits
;
54 #include "wmweather+.h"
63 #include "animation.h"
69 struct forecast
*cur_forecast
;
70 int window_X
, window_Y
;
74 #define M (((100/P)+1)*X)
75 static struct forecast
*last_fcst
;
76 static int last_font
=-1;
77 static time_t last_time
=0;
78 static int but_stat
=-1;
80 static int dclick_counter
=-1;
81 static time_t update_time
;
82 static int forecast_priority
, last_priority
;
83 static struct animation anim
;
84 static int counter_timer
=0;
85 static int show_counter
;
92 void DrawDisplay(int force
);
99 if(signal(SIGUSR2
, sigusr2
)==SIG_ERR
)
100 warn("Error setting SIGUSR2 signal handler!");
105 if(signal(SIGUSR1
, sigusr1
)==SIG_ERR
)
106 warn("Error setting SIGUSR1 signal handler!");
111 if(signal(i
, sigfunc
)==SIG_ERR
)
112 warn("Error setting %d signal handler!", i
);
115 void do_cleanup(void){
124 void init_dock(int argc
, char **argv
){
125 sscanf(wmweather_master_xpm
[0], "%d %d %*s", &wmweather_mask_width
, &wmweather_mask_height
);
126 wmweather_mask_bits
=malloc((wmweather_mask_width
+7)/8*wmweather_mask_height
);
127 if(!wmweather_mask_bits
) die("malloc failed");
128 createXBMfromXPM(wmweather_mask_bits
, wmweather_master_xpm
, wmweather_mask_width
, wmweather_mask_height
);
129 openDockWindow(argc
, argv
, wmweather_master_xpm
, wmweather_mask_bits
, wmweather_mask_width
, wmweather_mask_height
);
131 AddMouseRegion(0, 5, 5, 23, 14); /* Cur button */
132 AddMouseRegion(1, 23, 5, 41, 14); /* Fcst burron */
133 AddMouseRegion(2, 41, 5, 59, 14); /* Map button */
134 AddMouseRegion(3, 5, 17, 59, 59); /* Large window */
135 AddMouseRegion(4, 5, 17, 11, 24); /* left forecast arrow */
136 AddMouseRegion(5, 53, 17, 59, 24); /* right forecast arrow */
137 AddMouseRegion(6, 14, 17, 50, 24); /* forecast little window */
138 AddMouseRegion(7, 5, 27, 59, 59); /* forecast big window */
141 if(warning_zones
) init_warnings();
142 if(avn_station
) init_avn();
143 if(eta_station
) init_eta();
144 if(mrf_station
) init_mrf();
147 if(atexit(do_cleanup
)) warn("atexit() failed, files will not be cleaned up\n");
149 current_mode
=starting_mode
;
150 window_X
=0; window_Y
=0;
155 anim
.do_animate
=start_do_animation
;
169 if(signal(SIGUSR1
, sigusr1
)==SIG_ERR
)
170 warn("Error setting SIGUSR1 signal handler!");
171 if(signal(SIGUSR2
, sigusr2
)==SIG_ERR
)
172 warn("Error setting SIGUSR2 signal handler!");
173 if(signal(SIGHUP
, sigfunc
)==SIG_ERR
)
174 warn("Error setting SIGHUP signal handler!");
175 if(signal(SIGINT
, sigfunc
)==SIG_ERR
)
176 warn("Error setting SIGINT signal handler!");
177 if(signal(SIGPIPE
, sigfunc
)==SIG_ERR
)
178 warn("Error setting SIGPIPE signal handler!");
179 if(signal(SIGTERM
, sigfunc
)==SIG_ERR
)
180 warn("Error setting SIGTERM signal handler!");
195 if(j
&1) i
=current_mode
;
221 if(update_time
<time(NULL
)){
222 update_time
=time(NULL
)+2;
228 forecast_priority
=(forecast_priority
+1)%5;
231 if(counter_timer
>0) if(!--counter_timer
){
233 show_counter
=anim
.show_counter
=0;
236 if(dclick_counter
>-1) dclick_counter
--;
238 while(XPending(display
)){
239 XNextEvent(display
, &Event
);
247 XCloseDisplay(display
);
251 but_stat
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
252 if((dclick
!=but_stat
+1 && dclick
!=-but_stat
-1) || dclick_counter
<0){
255 } else if(dclick
==-but_stat
-1) dclick
=but_stat
+1;
261 if(current_mode
!=but_stat
){
262 current_mode
=but_stat
;
263 if(!anim
.do_animate
&& !show_counter
){
272 switch(Event
.xbutton
.button
){
275 if(radar_cross
!=NULL
){
282 anim
.do_animate
=!anim
.do_animate
;
284 if(!anim
.do_animate
&& current_mode
==1){
285 anim
.min_pct
=min_pct
;
286 show_counter
=anim
.show_counter
=1;
293 if(current_mode
==1 && !anim
.do_animate
&& min_pct
<100){
294 if(Event
.xbutton
.state
&ShiftMask
){
296 if(min_pct
>100) min_pct
=100;
298 anim
.min_pct
=min_pct
;
299 show_counter
=anim
.show_counter
=1;
306 if(current_mode
==1 && !anim
.do_animate
&& min_pct
>0){
307 if(Event
.xbutton
.state
&ShiftMask
){
309 if(min_pct
<0) min_pct
=0;
311 anim
.min_pct
=min_pct
;
320 show_counter
=anim
.show_counter
=1;
329 copyPixmapArea(123, 96, 6, 7, 65, 17);
332 copyPixmapArea(129, 96, 6, 7, 113, 17);
338 i
= CheckMouseRegion(Event
.xbutton
.x
, Event
.xbutton
.y
);
339 if(dclick_counter
<0) dclick
=0;
342 copyPixmapArea(123, 89, 6, 7, 65, 17);
345 copyPixmapArea(129, 89, 6, 7, 113, 17);
347 if(current_mode
==2 && (but_stat
==3 || but_stat
==7)
348 && Event
.xbutton
.button
==2){
353 if(but_stat
== i
&& but_stat
>= 0){
357 if(Event
.xbutton
.button
==1){
358 if(dclick
==but_stat
+1) kill(getpid(), SIGUSR1
);
359 else if(warning_zones
) output_warnings(0);
361 if(Event
.xbutton
.button
==2){
362 if(dclick
==but_stat
+1 && current_mode
==1){
363 show_counter
=anim
.show_counter
=!anim
.show_counter
;
368 if(Event
.xbutton
.button
==3 && warning_zones
) output_warnings(1);
369 if(Event
.xbutton
.button
==6){
370 show_counter
=anim
.show_counter
=0;
375 current_forecast_next(-1);
381 current_forecast_next(1);
387 if(Event
.xbutton
.button
==3) current_forecast_next(-1);
388 if(Event
.xbutton
.button
==2){{
389 struct forecast
*f
=current_forecast_get();
391 current_forecast_next(1);
392 while((g
=current_forecast_get())!=f
){
393 if((f
->hour
<0 && g
->hour
>=0) ||
394 (f
->hour
>=0 && g
->hour
<0)) break;
395 current_forecast_next(1);
398 if(Event
.xbutton
.button
==1) current_forecast_next(1);
410 setMaskXY(-window_X
, -window_Y
);
411 RedrawWindowXY(window_X
, window_Y
);
417 void DrawDisplay(int force
){
424 if(current_warnings
) font
=1;
425 if(force
|| last_font
!=font
) last_time
=-1;
428 switch(current_mode
){
430 if(last_time
==current
.last_update
) break;
431 last_time
=current
.last_update
;
432 EnableMouseRegion(3);
433 DisableMouseRegion(4);
434 DisableMouseRegion(5);
435 DisableMouseRegion(6);
436 DisableMouseRegion(7);
437 window_X
=0; window_Y
=0;
439 copyPixmapArea(124, 0, 54, 9, 5, 5);
440 copyPixmapArea(124, 9, 18, 9, 5, 5);
441 copyPixmapArea(124, 18, 54, 42, 5, 17);
443 DrawString(7, 17, metar_station
, font
+1);
444 if(current
.month
>0 && current
.month
<13 && current
.date
!=-1){
445 snprintf(bigbuf
, BIGBUF_LEN
, "%s %d", monthnames
[(int)current
.month
], current
.date
);
446 DrawString(32, 17, bigbuf
, font
+1);
448 if(current
.time
!=-1){
449 snprintf(bigbuf
, BIGBUF_LEN
, "%04dL (%04dZ)", current
.time
, local2utc(current
.time
, NULL
, NULL
, NULL
, NULL
));
450 DrawString(7, 23, bigbuf
, font
+1);
452 if(current
.temp
!=999){
453 x
=(temp_mode
==0)?temp_C2F(current
.temp
):current
.temp
;
456 snprintf(bigbuf
, BIGBUF_LEN
, "%d", x
);
457 DrawString(32, 29, bigbuf
, font
);
460 DrawChar(55, 29, '%', font
);
461 DrawNumber(54, 29, current
.rh
, font
);
463 if(current
.windspeed
==0){
464 x
=GetStringWidth("CALM");
465 DrawString(32+(26-x
)/2, 35, "CALM", font
);
467 if(current
.winddir
>=0 && current
.winddir
<=16){
468 x
=GetStringWidth(directions
[current
.winddir
]);
469 DrawString(45-x
, 35, directions
[current
.winddir
], font
);
471 switch(windspeed_mode
){
473 x
=knots2mph(current
.windspeed
);
476 x
=knots2kph(current
.windspeed
);
479 x
=knots2mps(current
.windspeed
);
482 x
=knots2beaufort(current
.windspeed
);
486 DrawNumber(58, 35, x
, font
);
488 if(current
.pressure
>0){
489 switch(pressure_mode
){
491 snprintf(bigbuf
, BIGBUF_LEN
, "P:%4.0f", inHg2hPa(current
.pressure
));
494 snprintf(bigbuf
, BIGBUF_LEN
, "P:%5.1f", inHg2mmHg(current
.pressure
));
497 snprintf(bigbuf
, BIGBUF_LEN
, "P:%5.3f", inHg2atm(current
.pressure
));
500 snprintf(bigbuf
, BIGBUF_LEN
, "P:%5.2f", current
.pressure
);
503 DrawString(32, 41, bigbuf
, font
);
505 if(current
.heatindex
!=999){
506 x
=(temp_mode
==0)?current
.heatindex
:temp_F2C(current
.heatindex
);
509 snprintf(bigbuf
, BIGBUF_LEN
, "HI: %d", x
);
510 DrawString(32, 47, bigbuf
, font
);
512 if(current
.windchill
!=999){
513 x
=(temp_mode
==0)?current
.windchill
:temp_F2C(current
.windchill
);
516 snprintf(bigbuf
, BIGBUF_LEN
, "WC: %d", x
);
517 DrawString(32, 53, bigbuf
, font
);
522 SetAnimation(&anim
, 5, 28, current
.sky
, current
.obs
, current
.vis
,
523 current
.frz
, current
.snow
, current
.rain
, current
.tstorm
, 0,
529 f
=current_forecast_get();
530 if(last_fcst
!=f
) last_time
=-1;
533 if(last_time
==f
->last_update
)
534 goto case_1_end
; /* still check bottom line priority */
535 else last_time
=f
->last_update
;
538 DisableMouseRegion(3);
539 EnableMouseRegion(4);
540 EnableMouseRegion(5);
541 EnableMouseRegion(6);
542 EnableMouseRegion(7);
543 window_X
=60; window_Y
=0;
546 copyPixmapArea(124, 0, 54, 9, 65, 5);
547 copyPixmapArea(142, 9, 18, 9, 83, 5);
548 copyPixmapArea(123, 89, 6, 7, 65, 17);
549 copyPixmapArea(129, 89, 6, 7, 113, 17);
550 copyPixmapArea(124, 18, 36, 7, 74, 17);
551 copyPixmapArea(124, 18, 54, 32, 65, 27);
558 if(tm
->tm_mon
+1==f
->month
&& tm
->tm_mday
==f
->day
){
559 if(f
->hour
<0) snprintf(bigbuf
, BIGBUF_LEN
, "TODAY");
560 else snprintf(bigbuf
, BIGBUF_LEN
, "TODAY %dL", f
->hour
);
564 fix_date(&x
, &y
, NULL
, NULL
);
565 if(x
==f
->month
&& y
==f
->day
){
566 if(f
->hour
<0) snprintf(bigbuf
, BIGBUF_LEN
, "TOMORROW");
567 else snprintf(bigbuf
, BIGBUF_LEN
, "TMRW %dL", f
->hour
);
573 fix_date(&x
, &y
, NULL
, NULL
);
574 if(x
==f
->month
&& y
==f
->day
){
575 if(f
->hour
<0) snprintf(bigbuf
, BIGBUF_LEN
, "%s",
576 wdaynames
[(int)f
->wday
]);
577 else snprintf(bigbuf
, BIGBUF_LEN
, "%.3s %dL",
578 wdaynames
[(int)f
->wday
], f
->hour
);
583 if(z
<99 && f
->month
>0 && f
->day
>0){
585 snprintf(bigbuf
, BIGBUF_LEN
, "%.3s %d",
586 monthnames
[(int)f
->month
], f
->day
);
587 else snprintf(bigbuf
, BIGBUF_LEN
, "%.3s %d %dL",
588 monthnames
[(int)f
->month
], f
->day
,
593 x
=GetStringWidth(bigbuf
);
594 DrawString(60+(64-x
)/2, 18, bigbuf
, font
);
596 x
=GetStringWidth(f
->station
);
597 DrawString(118-x
, 28, f
->station
, font
+1);
599 if(f
->high
!=999 || f
->low
!=999){
600 DrawChar(104, 35, '/', font
);
602 x
=(temp_mode
==0)?f
->high
:temp_F2C(f
->high
);
605 DrawNumber(103, 35, x
, font
);
608 x
=(temp_mode
==0)?f
->low
:temp_F2C(f
->low
);
611 DrawNumber(118, 35, x
, font
);
615 x
=(temp_mode
==0)?f
->temp
:temp_F2C(f
->temp
);
618 snprintf(bigbuf
, BIGBUF_LEN
, "%d", x
);
619 DrawString(92, 41, bigbuf
, font
);
622 DrawChar(115, 41, '%', font
);
623 DrawNumber(114, 41, f
->rh
, font
);
626 x
=GetStringWidth("CALM");
627 DrawString(92+(26-x
)/2, 47, "CALM", font
);
629 if(f
->winddir
>=0 && f
->winddir
<=16){
630 x
=GetStringWidth(directions
[f
->winddir
]);
631 DrawString(105-x
, 47, directions
[f
->winddir
], font
);
633 switch(windspeed_mode
){
635 x
=knots2mph(f
->windspeed
);
638 x
=knots2kph(f
->windspeed
);
641 x
=knots2mps(f
->windspeed
);
644 x
=knots2beaufort(f
->windspeed
);
648 DrawNumber(118, 47, x
, font
);
651 anim
.show_counter
=show_counter
;
652 anim
.min_pct
=min_pct
;
653 SetAnimation(&anim
, 65, 28, f
->sky
, f
->obs
, f
->vis
,
654 f
->frz
, f
->snow
, f
->rain
, f
->tstorm
, f
->svtstorm
,
658 if(f
==NULL
|| forecast_priority
==last_priority
) break;
660 /* This is a little tricky. We use the switch as a calculated goto
661 * (ick) to determine which order to try things in. Fall-through is
663 switch(forecast_priority
){
665 /* WTF? Oh well, just start at the beginning */
668 if(f
->heatindex
>=80 && f
->heatindex
!=999){
669 copyPixmapArea(124, 18, 26, 5, 92, 53);
670 x
=(temp_mode
==0)?f
->heatindex
:temp_F2C(f
->heatindex
);
671 snprintf(bigbuf
, BIGBUF_LEN
, "HI: %d", x
);
672 DrawString(92, 53, bigbuf
, font
);
678 if(f
->windchill
<=40 && f
->windchill
!=999){
679 copyPixmapArea(124, 18, 26, 5, 92, 53);
680 x
=(temp_mode
==0)?f
->windchill
:temp_F2C(f
->windchill
);
681 snprintf(bigbuf
, BIGBUF_LEN
, "WC: %d", x
);
682 DrawString(92, 53, bigbuf
, font
);
689 copyPixmapArea(124, 18, 26, 5, 92, 53);
690 if(f
->snowamt
==1){ x
=1; y
=2; }
691 else if(f
->snowamt
==8){ x
=8; y
=-1; }
692 else { x
=f
->snowamt
; y
=x
+2; }
694 x
=in2cm(x
); y
=in2cm(y
);
697 if(y
==-1) snprintf(bigbuf
, BIGBUF_LEN
, "SN:>%d", x
);
698 else snprintf(bigbuf
, BIGBUF_LEN
, "SN:%d-%d", x
, y
);
699 DrawString(92, 53, bigbuf
, font
);
706 copyPixmapArea(124, 18, 26, 5, 92, 53);
707 switch(f
->precipamt
){
709 if(length_mode
==0) DrawString(92, 53, "P:.01-.1", font
);
710 if(length_mode
==1) DrawString(92, 53, "P: 0-.25", font
);
713 if(length_mode
==0) DrawString(92, 53, "P:.1-.25", font
);
714 if(length_mode
==1) DrawString(92, 53, "P:.25-.6", font
);
717 if(length_mode
==0) DrawString(92, 53, "P:.25-.5", font
);
718 if(length_mode
==1) DrawString(92, 53, "P:.6-1.3", font
);
721 if(length_mode
==0) DrawString(92, 53, "P: .5-1", font
);
722 if(length_mode
==1) DrawString(92, 53, "P: 1-2.5", font
);
725 if(length_mode
==0) DrawString(92, 53, "P: 1-2", font
);
726 if(length_mode
==1) DrawString(92, 53, "P: 2.5-5", font
);
729 if(length_mode
==0) DrawString(92, 53, "P: >2", font
);
730 if(length_mode
==1) DrawString(92, 53, "P: >5", font
);
733 if(length_mode
==0) DrawString(92, 53, "P: >3", font
);
734 if(length_mode
==1) DrawString(92, 53, "P: >7.6", font
);
742 copyPixmapArea(124, 18, 26, 5, 92, 53);
743 x
=GetStringWidth("<")+1;
744 y
=GetStringWidth(f
->ID
)+1;
745 z
=GetStringWidth(">");
746 DrawChar(118-x
-y
-z
, 53, '<', font
+1);
747 DrawString(118-y
-z
, 53, f
->ID
, font
+1);
748 DrawChar(118-z
, 53, '>', font
+1);
752 last_priority
=forecast_priority
;
756 if(last_time
==radar_update_time
) break;
757 last_time
=radar_update_time
;
758 EnableMouseRegion(3);
759 DisableMouseRegion(4);
760 DisableMouseRegion(5);
761 DisableMouseRegion(6);
762 DisableMouseRegion(7);
763 window_X
=0; window_Y
=0;
765 copyPixmapArea(124, 0, 54, 9, 5, 5);
766 copyPixmapArea(160, 9, 18, 9, 41, 5);
767 put_radar(6, 18, font
);