1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <string.h>
5
6 #include "sunclock.h"
7 #include "langdef.h"
8
9 extern char * salloc();
10 extern void StringReAlloc();
11
12 extern char **get_dir_list();
13 extern int dup_strcmp();
14 extern void free_dirlist();
15
16 extern char * num2str();
17 extern void processKey();
18 extern int readVMF();
19 extern void buildMap();
20 extern int parseCmdLine();
21 extern void correctValues();
22 extern void getFonts();
23
24 extern void createGData();
25 extern void createGCs();
26 extern void clearNightArea();
27 extern void drawCities();
28 extern void drawSunAndMoon();
29 extern void drawDottedRectangle();
30
31 extern Display * dpy;
32 extern int scr;
33 extern Colormap cmap0, tmp_cmap;
34
35 extern int color_depth;
36 extern int runlevel;
37 extern int text_input;
38
39 extern Atom wm_delete_window;
40 extern Window Root, Menu, Filesel, Zoom, Option, Urban;
41 extern Pixmap zoompix, textpix, rootpix;
42 extern Pixel black, white;
43
44 extern Flags gflags;
45 extern ZoomSettings gzoom;
46
47 extern TextEntry option_entry, urban_entry[5];
48
49 extern struct Sundata *Seed;
50 extern struct Sundata *MenuCaller, *FileselCaller,
51 *ZoomCaller, *OptionCaller, *UrbanCaller, *RootCaller;
52 extern struct Geometry ClockGeom, MapGeom;
53 extern struct Geometry MenuGeom, FileselGeom, ZoomGeom, OptionGeom, UrbanGeom;
54
55 extern char * ProgName;
56 extern char * Title;
57 extern char * widget_type[7];
58 extern char * EditorCommand;
59
60 extern char * ClassName;
61 extern char * ClockClassName;
62 extern char * MapClassName;
63 extern char * AuxilClassName;
64
65 extern char * ExternAction;
66 extern char * CityInit;
67
68 extern char * share_maps_dir;
69 extern char ** dirtable;
70 extern char * image_dir;
71 extern char * Help[N_HELP];
72 extern char * Label[L_END];
73 extern char * FileselBanner[N_FILESEL];
74 extern char WeakChars[];
75
76 extern char language[4];
77
78 extern char * Clock_img_file;
79 extern char * Map_img_file;
80 extern char * Zoom_img_file;
81
82 extern int city_cat;
83 extern int *city_spotsizes;
84 extern int *city_sizelimits;
85 extern int do_menu, do_filesel, do_zoom, do_option, do_urban;
86 extern int do_dock, do_sync, do_zoomsync, do_root;
87
88 extern int placement;
89 extern int place_shiftx;
90 extern int place_shifty;
91
92 extern int verbose;
93 extern int button_pressed;
94 extern int option_changes;
95 extern int root_period;
96
97 extern int horiz_drift, vert_drift;
98 extern int label_shift, filesel_shift, zoom_shift;
99
100 extern int num_lines, num_table_entries;
101
102 extern int zoom_mode, zoom_active;
103
104 extern char menu_lasthint;
105 extern char option_lasthint;
106 extern char zoom_lasthint;
107 extern char urban_lasthint;
108
109 extern KeySym menu_newhint;
110 extern char option_newhint;
111 extern char zoom_newhint;
112 extern char urban_newhint;
113
114 extern long last_time;
115 extern long progress_value[6];
116
117 extern double darkness;
118 extern unsigned int adjust_dark;
119
120 extern int urban_t[5], urban_x[5], urban_y[5], urban_w[5];
121
122 int areaw, areah;
123 int urbanh;
124
125 void shutDown();
126
127 /* Is it really more secure than plain tmpnam() ?? */
128 void
secure_tmpnam(char * name)129 secure_tmpnam(char *name)
130 {
131 char compl[4];
132 static int order = 0;
133 compl[0] = 'a' + ((order/676)%26);
134 compl[1] = 'a' + ((order/26)%26);
135 compl[2] = 'a' + (order%26);
136 compl[3] = '\0';
137 ++order;
138 sprintf(name, "%s/XXXXXX", P_tmpdir);
139 close(mkstemp(name));
140 unlink(name);
141 strcat(name, compl);
142 }
143
144 void
showManual()145 showManual()
146 {
147 int i=0, j, k, l, c, cp;
148 char cmd[256];
149 char tmpname[80];
150 struct stat buf;
151 char *ptr, *text;
152 FILE *man;
153
154 secure_tmpnam(tmpname);
155 strcat(tmpname, "_sunclock.man");
156 sprintf(cmd, "man sunclock > %s", tmpname);
157 system(cmd);
158 man = fopen(tmpname, "r");
159 if (!man) {
160 unlink(tmpname);
161 return;
162 }
163 ptr = strdup(tmpname);
164 buf.st_mode = 0;
165 stat(ptr, &buf);
166 free(ptr);
167 text = malloc(buf.st_size+2);
168 if (!text) {
169 fclose(man);
170 return;
171 }
172 while ((c=fgetc(man))!=EOF) {
173 iter:
174 if (c=='_') {
175 cp = fgetc(man);
176 if (cp==EOF) break;
177 if (cp==8) continue;
178 text[i++] = (char)c;
179 c = cp;
180 goto iter;
181 } else
182 if (c==8) {
183 c = fgetc(man);
184 if (c==EOF) break;
185 } else
186 text[i++] = (char)c;
187 }
188 text[i] = '\0';
189 fclose(man);
190 man = fopen(tmpname, "w");
191 if (!man) {
192 free(text);
193 return;
194 }
195 for (j=0; j<i; j++) {
196 if (text[j]=='\n' && !strncmp(text+j+1, "Sunclock-", 6)) {
197 k = j;
198 while (isspace(text[k])) k--;
199 while (text[k]!='\n') k++;
200 ptr = strstr(text+j+1, "sunclock(1x)");
201 if (ptr) ptr = strstr(ptr+2, "sunclock(1x)");
202 if (ptr) {
203 j = ptr-text+1;
204 while (text[j]!='\n') j++;
205 while (isspace(text[j])) j++;
206 while (text[j]!='\n') j--;
207 for (l=k; l<j; l++) text[l] = '\0';
208 } else
209 for (l=k+3; l<j; l++) text[l] = '\0';
210 }
211 }
212 for (j=0; j<i; j++) {
213 if (text[j]) fputc(text[j], man);
214 }
215 free(text);
216 fflush(man);
217 fclose(man);
218 chmod(tmpname, 0555);
219 sprintf(cmd, "(%s %s ; rm -f %s ) &",
220 EditorCommand, tmpname, tmpname);
221 system(cmd);
222 }
223
224 int
getState(w)225 getState(w)
226 Window w;
227 {
228 XWindowAttributes xwa;
229 XGetWindowAttributes(dpy, w, &xwa);
230 return xwa.map_state;
231 }
232
233 int
getPlacement(win,x,y,w,h)234 getPlacement(win, x, y, w, h)
235 Window win;
236 int *x, *y;
237 unsigned int *w, *h;
238 {
239 int xp, yp;
240 unsigned int b, d, n;
241 Window junk, root, parent, *children;
242
243 XFlush(dpy);
244 XQueryTree(dpy, win, &root, &parent, &children, &n);
245 if (!parent) {
246 fprintf(stderr, "Cannot query window tree!\n");
247 return 1;
248 }
249
250 if (parent == root) parent = win;
251
252 XGetGeometry(dpy, parent, &root, x, y, w, h, &b, &d);
253
254 XTranslateCoordinates(dpy, win, parent, 0, 0, x, y, &junk);
255 if (2*(*x) < *w) *w -= 2*(*x);
256 if ((*x)+(*y) < *h) *h -= (*x) + (*y);
257 XTranslateCoordinates(dpy, win, root, 0, 0, x, y, &junk);
258 XTranslateCoordinates(dpy, parent, root, 0, 0, &xp, &yp, &junk);
259
260 horiz_drift = *x - xp;
261 vert_drift = *y - yp;
262 /*
263 if (verbose) {
264 fprintf(stderr, "Window placement (%d,%d)\n", *x, *y);
265 fprintf(stderr, "Window drift (%d,%d)\n", horiz_drift, vert_drift);
266 }
267 */
268 return 0;
269 }
270
271 void
272 checkGeom(Context, bool)
273 struct Sundata * Context;
274 int bool;
275 {
276 int a, b;
277
278 a = DisplayWidth(dpy, scr) - Context->geom.width - horiz_drift - 5;
279 b = DisplayHeight(dpy, scr) - Context->geom.height
280 - Context->hstrip - vert_drift - 5;
281 if (Context->geom.x > a) Context->geom.x = a;
282 if (Context->geom.y > b) Context->geom.y = b;
283 if (Context->geom.x < 0) Context->geom.x = 5;
284 if (Context->geom.y < 0) Context->geom.y = 5;
285 if (bool) Context->geom.mask =
286 XValue | YValue | WidthValue | HeightValue;
287 }
288
289 void
adjustGeom(Context,which)290 adjustGeom(Context, which)
291 struct Sundata * Context;
292 int which;
293 {
294 int x, y, dx=0, dy=0, diff;
295 unsigned int w, h;
296
297 if (getPlacement(Context->win, &x, &y, &w, &h)) return;
298
299 if (which) {
300 diff= MapGeom.height - ClockGeom.height +
301 Context->gdata->mapstrip - Context->gdata->clockstrip;
302 switch(placement) {
303 case CENTER:
304 dx = (MapGeom.width - ClockGeom.width)/2;
305 dy = diff/2;
306 break;
307 case NE:
308 dx = MapGeom.width - ClockGeom.width;
309 break;
310 case SE:
311 dx = MapGeom.width - ClockGeom.width;
312 case SW:
313 dy = diff;
314 break;
315 default:
316 break;
317 }
318 }
319
320 if (placement) {
321 dx = dx - place_shiftx;
322 dy = dy - place_shifty;
323 if (Context->wintype) {
324 dx = -dx;
325 dy = -dy;
326 }
327 if (placement >= CENTER) {
328 Context->geom.x = x + dx - horiz_drift;
329 Context->geom.y = y + dy - vert_drift;
330 checkGeom(Context, 1);
331 }
332 }
333 }
334
335 /*
336 * Set up stuff the window manager will want to know. Must be done
337 * before mapping window, but after creating it.
338 */
339
340 void
setSizeHints(Context,num)341 setSizeHints(Context, num)
342 struct Sundata * Context;
343 int num;
344 {
345 XSizeHints xsh;
346 struct Geometry * Geom = NULL;
347 Window win = 0;
348
349 if (num<=1) {
350 if (!Context) return;
351 win = Context->win;
352 Geom = &Context->geom;
353 xsh.flags = PSize | PMinSize;
354 if (Geom->mask & (XValue | YValue)) {
355 xsh.x = Geom->x;
356 xsh.y = Geom->y;
357 xsh.flags |= USPosition;
358 }
359 xsh.width = Geom->width;
360 xsh.height = Geom->height + Context->hstrip;
361 if (do_dock && Context==Seed) {
362 xsh.max_width = xsh.min_width = xsh.width;
363 xsh.max_height = xsh.min_height = xsh.height;
364 xsh.flags |= PMaxSize | PMinSize;
365 } else {
366 xsh.min_width = Geom->w_mini;
367 xsh.min_height = Geom->h_mini + Context->hstrip;
368 }
369 } else
370 if (num>=2) {
371 xsh.flags = PSize | USPosition | PMinSize;
372 if (num==2) {
373 win = Menu;
374 Geom = &MenuGeom;
375 xsh.flags |= PMaxSize;
376 xsh.min_width = xsh.max_width = Geom->width;
377 xsh.min_height = xsh.max_height = Geom->height;
378 }
379 if (num==3) {
380 win = Filesel;
381 Geom = &FileselGeom;
382 xsh.min_width = Geom->w_mini;
383 xsh.min_height = Geom->h_mini;
384 }
385 if (num==4) {
386 win = Zoom;
387 Geom = &ZoomGeom;
388 xsh.min_width = Geom->w_mini;
389 xsh.min_height = Geom->h_mini;
390 }
391 if (num==5) {
392 win = Option;
393 Geom = &OptionGeom;
394 xsh.flags |= PMaxSize;
395 xsh.min_width = Geom->w_mini;
396 xsh.max_width = 2000;
397 xsh.min_height = xsh.max_height = Geom->h_mini;
398 }
399 if (num==6) {
400 win = Urban;
401 Geom = &UrbanGeom;
402 xsh.flags |= PMaxSize;
403 xsh.max_width = 2000;
404 xsh.min_width = Geom->w_mini;
405 xsh.min_height = xsh.max_height = Geom->h_mini;
406 }
407 xsh.x = Geom->x;
408 xsh.y = Geom->y;
409 xsh.width = Geom->width;
410 xsh.height = Geom->height;
411 }
412
413 if (!win) return;
414 XSetNormalHints(dpy, win, &xsh);
415 }
416
417 void
setClassHints(win,num)418 setClassHints(win, num)
419 Window win;
420 int num;
421 {
422 char *titlename, *iconname;
423 XClassHint xch;
424
425 titlename = NULL;
426 if (!Title) StringReAlloc(&Title, ProgName);
427
428 if (!ClassName) {
429 StringReAlloc(&ClassName, ProgName);
430 *ClassName = toupper(*ClassName);
431 }
432
433 if (ClassName && !ClockClassName)
434 StringReAlloc(&ClockClassName, ClassName);
435
436 if (ClassName && !MapClassName)
437 StringReAlloc(&MapClassName, ClassName);
438
439 if (ClassName && !AuxilClassName)
440 StringReAlloc(&AuxilClassName, ClassName);
441
442 if (num == 0)
443 xch.res_class = ClockClassName;
444 else
445 if (num == 1)
446 xch.res_class = MapClassName;
447 else
448 xch.res_class = AuxilClassName;
449
450 xch.res_name = ProgName;
451
452 XSetClassHint(dpy, win, &xch);
453
454 iconname = (char *)
455 salloc((strlen(Title)+strlen(VERSION)+10)*sizeof(char));
456 sprintf(iconname, "%s %s", Title, VERSION);
457 XSetIconName(dpy, win, iconname);
458 free(iconname);
459
460 titlename = (char *)
461 salloc((strlen(Title)+20)*sizeof(char));
462 sprintf(titlename, "%s / %s", Title, widget_type[num]);
463 XStoreName(dpy, win, titlename);
464 free(titlename);
465 }
466
467 void
setProtocols(Context,num)468 setProtocols(Context, num)
469 struct Sundata * Context;
470 int num;
471 {
472 Window win = 0;
473 long mask;
474
475 mask = FocusChangeMask | VisibilityChangeMask | ExposureMask |
476 StructureNotifyMask |
477 ButtonPressMask | ButtonReleaseMask | KeyPressMask;
478
479 if (num>=1)
480 mask |= PointerMotionMask;
481
482 /* use StructureNotifyMask rather than ResizeRedirectMask
483 to avoid bug in some window mangers... as enlightenment !
484 All events would be:
485 for (i=0; i<=24; i++) mask |= 1L<<i;
486 */
487
488 switch(num) {
489
490 case 0:
491 case 1:
492 if (!Context) return;
493 mask |= EnterWindowMask | LeaveWindowMask;
494 win = Context->win;
495 break;
496
497 case 2:
498 win = Menu;
499 break;
500
501 case 3:
502 win = Filesel;
503 break;
504
505 case 4:
506 win = Zoom;
507 break;
508
509 case 5:
510 win = Option;
511 mask |= KeyReleaseMask;
512 break;
513
514 case 6:
515 win = Urban;
516 mask |= KeyReleaseMask;
517 break;
518
519 default:
520 break;
521 }
522
523 if (!win) return;
524
525 XSelectInput(dpy, win, mask);
526 XSetWMProtocols(dpy, win, &wm_delete_window, 1);
527 }
528
529 Window
newWindow(Context,Geom,num)530 newWindow(Context, Geom, num)
531 struct Sundata * Context;
532 struct Geometry * Geom;
533 int num;
534 {
535 Window win = 0;
536 int strip;
537
538 if (num<=1) {
539 strip = (num)? Context->gdata->mapstrip :
540 Context->gdata->clockstrip;
541 Context->hstrip = strip;
542 if (Geom->mask & XNegative)
543 Geom->x = DisplayWidth(dpy, scr) - Geom->width + Geom->x;
544 if (Geom->mask & YNegative)
545 Geom->y = DisplayHeight(dpy, scr) - Geom->height + Geom->y-strip;
546 } else
547 strip = 0;
548
549 win = XCreateSimpleWindow(dpy, Root,
550 Geom->x, Geom->y,
551 Geom->width, Geom->height + strip, 0,
552 black, white);
553 if (win) setClassHints(win, num);
554 return win;
555 }
556
getWinParams(win,Context,keys,nkeys,y,width)557 void getWinParams(win, Context, keys, nkeys, y, width)
558 Window win;
559 struct Sundata **Context;
560 char **keys;
561 int *nkeys;
562 int *y;
563 int *width;
564 {
565 *Context = NULL;
566 if (win==Menu) {
567 *Context = MenuCaller;
568 *keys = MenuKey;
569 *nkeys = N_MENU;
570 *y = 0;
571 *width = MenuGeom.width;
572 }
573 if (win==Option) {
574 *Context = OptionCaller;
575 *keys = OptionKey;
576 *nkeys = N_OPTION;
577 *y = OptionGeom.height-2*OptionCaller->gdata->menustrip - 1;
578 *width = OptionGeom.width;
579 }
580 if (win==Zoom) {
581 *Context = ZoomCaller;
582 *keys = ZoomKey;
583 *nkeys = N_ZOOM;
584 *y = areah+64;
585 *width = ZoomGeom.width;
586 }
587 if (win==Urban) {
588 *Context = UrbanCaller;
589 *keys = UrbanKey;
590 *nkeys = N_URBAN;
591 *y = urbanh;
592 *width = UrbanGeom.width;
593 }
594 if (win==Filesel) {
595 *Context = FileselCaller;
596 *keys = WeakChars;
597 *nkeys = 6;
598 *y = 0;
599 *width = FileselGeom.width;
600 }
601 }
602
603 int
getButton(win,x,y)604 getButton(win, x, y)
605 Window win;
606 int x, y;
607 {
608 struct Sundata * Context=NULL;
609 char *keys=NULL;
610 int nkeys=0;
611 int y1, w0, n, i, j=0, b, d;
612 getWinParams(win, &Context, &keys, &nkeys, &y1, &w0);
613 n = -1;
614 if (y<=y1 || y>=y1+Context->gdata->menustrip) return n;
615 b = 0;
616 d = Context->gdata->charspace;
617 if (win==Filesel) d = 2*d;
618 for (i=0; i<nkeys; i++) {
619 j = i*d + b;
620 b += 5*(keys[2*i+1]==';');
621 if (x>j && x<j+d) {
622 n = i;
623 break;
624 }
625 }
626 if (x>j+d+5) n = nkeys;
627 return n;
628 }
629
630 void
drawBox(win,gc,pix,x1,y1,x2,y2,clicked)631 drawBox(win, gc, pix, x1, y1, x2, y2, clicked)
632 Window win;
633 GC gc;
634 Pixel *pix;
635 int x1, y1, x2, y2;
636 int clicked;
637 {
638 XSetForeground(dpy, gc, pix[BUTTONCOLOR]);
639 XFillRectangle(dpy, win, gc, x1, y1, x2-x1, y2-y1);
640
641 XSetForeground(dpy, gc, pix[(clicked)?BUTTONFGCOLOR1:BUTTONFGCOLOR3]);
642 XDrawLine(dpy, win, gc, x1, y1, x1, y2);
643 XDrawLine(dpy, win, gc, x1, y1, x2, y1);
644
645 XSetForeground(dpy, gc, pix[(clicked)?BUTTONFGCOLOR2:BUTTONFGCOLOR4]);
646 XDrawLine(dpy, win, gc, x1+1, y1+1, x1+1, y2-1);
647 XDrawLine(dpy, win, gc, x1+1, y1+1, x2-1, y1+1);
648
649 XSetForeground(dpy, gc, pix[(clicked)?BUTTONFGCOLOR4:BUTTONFGCOLOR2]);
650 XDrawLine(dpy, win, gc, x1+1, y2-1, x2-1, y2-1);
651 XDrawLine(dpy, win, gc, x2-1, y1+1, x2-1, y2-1);
652
653 XSetForeground(dpy, gc, pix[(clicked)?BUTTONFGCOLOR3:BUTTONFGCOLOR1]);
654 XDrawLine(dpy, win, gc, x1, y2, x2, y2);
655 XDrawLine(dpy, win, gc, x2, y1, x2, y2);
656 }
657
658 void
drawButton(win,n,clicked)659 drawButton(win, n, clicked)
660 Window win;
661 int n;
662 int clicked;
663 {
664 int i, j=0, b, d, x1=0, y1=0, x2=0, y2=0, x, y, w0=0;
665 struct Sundata * Context=NULL;
666 char c[2] = { '\0', '\0'};
667 char *s = c;
668 char *keys=NULL;
669 int nkeys=0;
670 int charspace;
671
672 getWinParams(win, &Context, &keys, &nkeys, &y1, &w0);
673 if (!Context) return;
674 charspace = Context->gdata->charspace;
675 if (win==Filesel) charspace = 2*charspace;
676
677 b = 0;
678 for (i=0; i<=n; i++) {
679 j = i*charspace + b;
680 if (win!=Filesel)
681 b += 5*((i==nkeys-1) || (keys[2*i+1]==';'));
682 }
683 x1 = j;
684 y2 = y1+Context->gdata->menustrip;
685 if (n>=0 && n<nkeys) {
686 if (win==Filesel)
687 s = FileselBanner[n];
688 else {
689 c[0] = keys[2*n];
690 }
691 x2 = j+charspace-1;
692 } else {
693 if (win==Zoom && n==nkeys+1) {
694 c[0] = (zoom_active)?'+':'-';
695 x1 = areah+170,
696 y1 = 21;
697 x2 = x1+charspace;
698 y2 = y1+18;
699 } else {
700 s = Label[L_ESCAPE];
701 x2 = w0 - 1;
702 }
703 }
704
705 if (clicked<=-1) {
706 XSetForeground(dpy, Context->gdata->wingc,
707 Context->gdata->pixel[(clicked==-2)?
708 BUTTONCOLOR:MENUFGCOLOR]);
709 for (y=y1+2; y<=y2-3; y+=y2-y1-5)
710 for (x=x1+4; x<=x2-3; x++)
711 if ((x+y)&1) XDrawPoint(dpy, win,
712 Context->gdata->wingc, x, y);
713 for (y=y1+2; y<=y2-3; y++)
714 for (x=x1+4; x<=x2-3; x+=x2-x1-7)
715 if ((x+y)&1) XDrawPoint(dpy, win,
716 Context->gdata->wingc, x, y);
717 return;
718 }
719
720 drawBox(win, Context->gdata->wingc,
721 Context->gdata->pixel, x1, y1, x2, y2, clicked);
722
723 d = (5*Context->gdata->charspace)/12;
724 XSetBackground(dpy, Context->gdata->wingc,
725 Context->gdata->pixel[BUTTONCOLOR]);
726
727 if (win==Menu && do_dock && (s[0]==c[0]) && index(WeakChars,c[0]))
728 XSetForeground(dpy, Context->gdata->wingc,
729 Context->gdata->pixel[WEAKCOLOR]);
730 else
731 XSetForeground(dpy, Context->gdata->wingc,
732 Context->gdata->pixel[MENUFGCOLOR]);
733
734 XDrawImageString(dpy, win, Context->gdata->wingc,
735 x1+d,
736 y1+Context->gdata->font[MENUFONT]->max_bounds.ascent + 4,
737 s, strlen(s));
738 }
739
740 int
getNumCmd(key)741 getNumCmd(key)
742 char key;
743 {
744 int i;
745 for (i=0; i<N_HELP; i++)
746 if (key==CommandKey[i]) return i;
747 return -1;
748 }
749
750 void
BasicSettings(Context)751 BasicSettings(Context)
752 Sundata * Context;
753 {
754 XSetBackground(dpy, Context->gdata->wingc, Context->gdata->pixel[MENUBGCOLOR]);
755 XSetForeground(dpy, Context->gdata->wingc, Context->gdata->pixel[MENUFGCOLOR]);
756 XSetFont(dpy, Context->gdata->wingc, Context->gdata->font[MENUFONT]->fid);
757 }
758
759 void
helpHint(Context,key,hint)760 helpHint(Context, key, hint)
761 Sundata * Context;
762 char key;
763 char *hint;
764 {
765 int i,j,k,l;
766 char more[128], prog_str[60];
767
768 if (key=='\033')
769 sprintf(hint, " %s", Label[L_ESCMENU]);
770 else
771 if (key==' ')
772 sprintf(hint, " %s", Label[L_CONTROLS]);
773 else {
774 i = getNumCmd(key);
775 if (i>=0)
776 sprintf(hint, " %s", Help[i]);
777 else
778 sprintf(hint, " %s", Label[L_UNKNOWN]);
779 }
780
781 more[0] = more[1] = ' ';
782 more[2] = '\0';
783
784 if (index("CDS", key))
785 sprintf(more, " (%s)", Label[L_DEGREE]);
786 if (index("ABGJ'", key)) {
787 switch(Context->flags.progress) {
788 case 0: sprintf(prog_str, "1 %s", Label[L_MIN]); break;
789 case 1: sprintf(prog_str, "1 %s", Label[L_HOUR]); break;
790 case 2: sprintf(prog_str, "1 %s", Label[L_DAY]); break;
791 case 3: sprintf(prog_str, "7 %s", Label[L_DAYS]); break;
792 case 4: sprintf(prog_str, "30 %s", Label[L_DAYS]); break;
793 case 5: sprintf(prog_str, "%ld %s",
794 progress_value[5], Label[L_SEC]); break;
795 }
796 sprintf(more, " ( %s %s%s %s %.3f %s )",
797 Label[L_PROGRESS],
798 (key=='A')? "+":((key=='B')? "-":""), prog_str,
799 Label[L_TIMEJUMP], Context->jump/86400.0,
800 Label[L_DAYS]);
801 }
802 if (key == 'H') {
803 sscanf(RELEASE, "%d %d %d", &i, &j, &k);
804 sprintf(more+1, "(%s %s, %d %s %d, %s)",
805 ProgName, VERSION, i, Month_name[j-1], k, COPYRIGHT);
806 }
807 if (key == 'X') {
808 more[1] = ':';
809 more[2] = ' ';
810 if (ExternAction)
811 strncpy(more+3, ExternAction, 123);
812 else
813 strcpy(more, "(null)");
814 more[126] = '0';
815 }
816
817 if (key == '=')
818 sprintf(more+2, "(%c)", (do_sync)? '+' : '-');
819 if (key == '[' && do_root <= 0)
820 sprintf(more+2, Label[L_ONCE]);
821 if (key == '[' && do_root >= 1)
822 sprintf(more+2, Label[L_PERIODIC], root_period);
823 if (key == ']' && do_root <= 0)
824 sprintf(more+2, Label[L_BLANKSCREEN]);
825 if (key == ']' && do_root >= 1)
826 sprintf(more+2, Label[L_STARRYSKY]);
827 if (more[2])
828 strncat(hint, more, 120 - strlen(hint));
829 l = strlen(hint);
830 if (l<120)
831 for (i=l; i<120; i++) hint[i] = ' ';
832 hint[120] = '\0';
833 }
834
835 void
showMenuHint(but_pos)836 showMenuHint(but_pos)
837 int but_pos;
838 {
839 static int move_pos = -1;
840 char key;
841 char hint[128];
842
843 if (!do_menu) return;
844 if (!MenuCaller) return;
845
846 if (menu_newhint == XK_Shift_L || menu_newhint == XK_Shift_R) return;
847 key = toupper((char) menu_newhint);
848
849 if (move_pos>=0) drawButton(Menu, move_pos, -2);
850 if (but_pos>=0) drawButton(Menu, but_pos, -1);
851 move_pos = but_pos;
852
853 if (key == menu_lasthint) return;
854 helpHint(MenuCaller, key, hint);
855
856 menu_lasthint = key;
857 BasicSettings(MenuCaller);
858 XDrawImageString(dpy, Menu, MenuCaller->gdata->wingc, 4,
859 MenuCaller->gdata->font[MENUFONT]->max_bounds.ascent +
860 MenuCaller->gdata->menustrip + 4,
861 hint, strlen(hint));
862 }
863
864 void
setupMenu(mode)865 setupMenu(mode)
866 int mode;
867 {
868 int i, l;
869 static int j=-1;
870 static char c;
871
872 if (!do_menu) return;
873
874 if (j>=0) WeakChars[j] = c;
875 l = strlen(WeakChars);
876
877 if (MenuCaller->wintype) {
878 if (do_dock) j = 1; else j = 0;
879 } else {
880 j = -1;
881 if (do_dock) {
882 if (MenuCaller != Seed) j = l-4;
883 } else j = l-5;
884 }
885 if (j>=0) {
886 c = WeakChars[j] ;
887 WeakChars[j] = '\0';
888 }
889
890 BasicSettings(MenuCaller);
891 XSetWindowColormap(dpy, Menu, MenuCaller->gdata->cmap);
892 XSetWindowBackground(dpy, Menu, MenuCaller->gdata->pixel[MENUBGCOLOR]);
893 XClearArea(dpy, Menu, 0, 0, MenuGeom.width, MenuGeom.height, False);
894
895 for (i=0; i<=N_MENU; i++)
896 drawButton(Menu, i, 0);
897 menu_lasthint = '\0';
898 showMenuHint(-1);
899 }
900
901 void
PopMenu(Context)902 PopMenu(Context)
903 struct Sundata * Context;
904 {
905 int w, h, a, b, x=0, y=0;
906
907 do_menu = 1 - do_menu;
908
909 if (!do_menu)
910 {
911 XDestroyWindow(dpy, Menu);
912 Menu = 0;
913 MenuCaller = NULL;
914 return;
915 }
916
917 if (!Menu)
918 Menu = newWindow(NULL, &MenuGeom, 2);
919
920 XSelectInput(dpy, Menu, 0);
921 MenuCaller = Context;
922
923 MenuGeom.width = MENU_WIDTH * Context->gdata->menustrip - 6;
924 MenuGeom.height = 2 * Context->gdata->menustrip;
925
926 if (!getPlacement(Context->win, &Context->geom.x,
927 &Context->geom.y, &w, &h)) {
928 x = Context->geom.x + MenuGeom.x - horiz_drift - 5;
929 a = Context->geom.y + h + 6;
930
931 b = Context->geom.y - MenuGeom.height - MenuGeom.y - 2*vert_drift - 28;
932 if (b < TOPTITLEBARHEIGHT ) b = TOPTITLEBARHEIGHT;
933 if (a > (int) DisplayHeight(dpy,scr)
934 - 2*MenuGeom.height -vert_drift -20)
935 a = b;
936 y = (placement<=NE)? a : b;
937 }
938 setSizeHints(NULL, 2);
939 XMoveWindow(dpy, Menu, x, y);
940 XMapWindow(dpy, Menu);
941 XMoveWindow(dpy, Menu, x, y);
942 XFlush(dpy);
943 usleep(2*TIMESTEP);
944 menu_lasthint = ' ';
945 setupMenu(-1);
946 setProtocols(NULL, 2);
947 }
948
949 void
processMenuAction(Context,x,y,button,evtype)950 processMenuAction(Context, x, y, button, evtype)
951 Sundata * Context;
952 int x, y, button, evtype;
953 {
954 static int click_pos = -1;
955 int but_pos;
956 KeySym key;
957 if (evtype == ButtonRelease && click_pos>=0) {
958 drawButton(Menu, click_pos, 0);
959 click_pos = -1;
960 }
961 but_pos = getButton(Menu, x, y);
962 if (evtype == ButtonPress && but_pos>=0 && but_pos<=N_MENU) {
963 drawButton(Menu, but_pos, 1);
964 click_pos = but_pos;
965 return;
966 }
967 if (evtype == MotionNotify) {
968 if (but_pos >= N_MENU) {
969 menu_newhint = XK_Escape;
970 showMenuHint(N_MENU);
971 return;
972 }
973 if (but_pos <= -1)
974 menu_newhint = ' ';
975 else
976 menu_newhint = MenuKey[2*but_pos];
977 showMenuHint(getNumCmd(menu_newhint));
978 return;
979 }
980 if (but_pos==-1) return;
981 if (do_menu && but_pos >= N_MENU) {
982 PopMenu(MenuCaller);
983 return;
984 }
985 key = MenuKey[2*but_pos];
986 if (button<=2) key = tolower(key);
987 processKey(Menu, (KeySym)key);
988 }
989
990 void
clearFileselPartially()991 clearFileselPartially()
992 {
993 XSetWindowBackground(dpy, Filesel, FileselCaller->gdata->pixel[MENUBGCOLOR]);
994 XClearArea(dpy, Filesel, 0, FileselCaller->gdata->menustrip+1,
995 FileselGeom.width-2, FileselGeom.height-FileselCaller->gdata->menustrip-2, False);
996 }
997
998 void
setupFilesel(mode)999 setupFilesel(mode)
1000 int mode;
1001 {
1002 int i, j, b, d, p, w, h, ht, skip;
1003 char *s, *sp;
1004
1005 if (!do_filesel) return;
1006
1007 XSetWindowColormap(dpy, Filesel, FileselCaller->gdata->cmap);
1008 XSetWindowBackground(dpy, Filesel,
1009 FileselCaller->gdata->pixel[MENUBGCOLOR]);
1010
1011 d = FileselCaller->gdata->charspace/3;
1012 h = FileselCaller->gdata->menustrip;
1013
1014 if (mode < 0) {
1015 BasicSettings(FileselCaller);
1016 XClearArea(dpy, Filesel, 0, 0,
1017 FileselGeom.width, FileselGeom.height, False);
1018 for (i=0; i<=6; i++)
1019 drawButton(Filesel, i, 0);
1020 }
1021
1022 BasicSettings(FileselCaller);
1023
1024 if (mode <= 0) {
1025 XClearArea(dpy, Filesel, 0, FileselCaller->gdata->menustrip+1,
1026 FileselGeom.width - 15, FileselGeom.height, False);
1027 XClearArea(dpy, Filesel,
1028 FileselGeom.width - 15, FileselCaller->gdata->menustrip+1,
1029 13, FileselCaller->gdata->menustrip, False);
1030 XSetForeground(dpy, FileselCaller->gdata->wingc,
1031 FileselCaller->gdata->pixel[MENUFGCOLOR]);
1032 XDrawImageString(dpy, Filesel, FileselCaller->gdata->wingc,
1033 d, FileselCaller->gdata->font[MENUFONT]->max_bounds.ascent +
1034 FileselCaller->gdata->menustrip+4,
1035 image_dir, strlen(image_dir));
1036
1037 h = 2*FileselCaller->gdata->menustrip;
1038 XDrawLine(dpy, Filesel, FileselCaller->gdata->wingc,
1039 0, h, FileselGeom.width, h);
1040
1041 XDrawLine(dpy, Filesel, FileselCaller->gdata->wingc,
1042 FileselGeom.width - 15, 2*FileselCaller->gdata->menustrip,
1043 FileselGeom.width - 15, FileselGeom.height);
1044 /* Drawing small triangular icons */
1045 w = FileselGeom.width - 7;
1046 h = 2 * FileselCaller->gdata->menustrip + 1;
1047 for (i=0; i<=10; i++)
1048 XDrawLine(dpy, Filesel, FileselCaller->gdata->wingc,
1049 w-i/2, h+i, w+i/2, h+i);
1050 h = FileselGeom.height-1;
1051 for (i=0; i<=10; i++)
1052 XDrawLine(dpy, Filesel, FileselCaller->gdata->wingc,
1053 w-i/2, h-i, w+i/2, h-i);
1054 }
1055
1056 if (mode<=1)
1057 XClearArea(dpy, Filesel, 0, 2*FileselCaller->gdata->menustrip+1,
1058 FileselGeom.width - 15, FileselGeom.height, False);
1059
1060 if (!dirtable)
1061 dirtable = get_dir_list(image_dir, &num_table_entries);
1062 if (dirtable)
1063 qsort(dirtable, num_table_entries, sizeof(char *), dup_strcmp);
1064 else {
1065 char error[] = "Directory inexistent or inaccessible !!!";
1066 XSetForeground(dpy, FileselCaller->gdata->wingc,
1067 FileselCaller->gdata->pixel[IMAGECOLOR]);
1068 XDrawImageString(dpy, Filesel,
1069 FileselCaller->gdata->wingc, d,
1070 3*FileselCaller->gdata->menustrip,
1071 error, strlen(error));
1072 return;
1073 }
1074
1075 skip = (3*FileselCaller->gdata->menustrip)/4;
1076 num_lines = (FileselGeom.height-2*FileselCaller->gdata->menustrip)/skip;
1077 /* drawing the thumb */
1078 XSetForeground(dpy, FileselCaller->gdata->wingc,
1079 FileselCaller->gdata->pixel[ZOOMBGCOLOR]);
1080 XFillRectangle(dpy, Filesel, FileselCaller->gdata->wingc,
1081 FileselGeom.width - 14, 2*FileselCaller->gdata->menustrip+12,
1082 14, FileselGeom.height-2*FileselCaller->gdata->menustrip-23);
1083
1084 w = FileselGeom.width - 12;
1085 p = FileselGeom.height - 2 * FileselCaller->gdata->menustrip - 28;
1086 ht = p * (num_lines+1) / (num_table_entries+1);
1087 if (ht<20) ht = 20;
1088 if (ht>p/2) ht = p/2;
1089 p = p - ht;
1090 h = 2 * FileselCaller->gdata->menustrip + 14;
1091 if (num_table_entries>2)
1092 h += (filesel_shift * p)/(num_table_entries-2);
1093 drawBox(Filesel, FileselCaller->gdata->wingc,
1094 FileselCaller->gdata->pixel, w, h, w+9, h+ht, 0);
1095
1096 for (i=0; i<num_table_entries-filesel_shift; i++)
1097 if (i<num_lines) {
1098 s = dirtable[i+filesel_shift];
1099 b = (s[strlen(s)-1]=='/');
1100 if (b==0) {
1101 if (strstr(s,".gif") || strstr(s,".jpg") ||
1102 strstr(s,".png") || strstr(s,".xpm") ||
1103 strstr(s,".vmf"))
1104 b=2;
1105 }
1106 j = FileselCaller->gdata->font[MENUFONT]->max_bounds.ascent +
1107 2 * FileselCaller->gdata->menustrip + i*skip + 3;
1108 sp = (FileselCaller->wintype)?
1109 FileselCaller->map_img_file : FileselCaller->clock_img_file;
1110 if (strstr(sp,s)) {
1111 if (mode<=3)
1112 XClearArea(dpy, Filesel, 2,
1113 /* FileselCaller->gdata->font[MENUFONT]->max_bounds.ascent+ */
1114 2 * FileselCaller->gdata->menustrip + 1, 3,
1115 FileselGeom.height, False);
1116 if (mode==3) {
1117 XSetForeground(dpy, FileselCaller->gdata->wingc,
1118 FileselCaller->gdata->pixel[CHANGECOLOR]);
1119 XDrawRectangle(dpy, Filesel, FileselCaller->gdata->wingc,
1120 d/4, j-FileselCaller->gdata->font[MENUFONT]->max_bounds.ascent/2, 3,4);
1121 } else {
1122 XSetForeground(dpy, FileselCaller->gdata->wingc,
1123 FileselCaller->gdata->pixel[CHOICECOLOR]);
1124 XFillRectangle(dpy, Filesel, FileselCaller->gdata->wingc,
1125 d/4, j-FileselCaller->gdata->font[MENUFONT]->max_bounds.ascent/2, 3,4);
1126 }
1127 }
1128 if (mode<=1) {
1129 XSetForeground(dpy, FileselCaller->gdata->wingc,
1130 (b==0)? FileselCaller->gdata->pixel[MENUFGCOLOR] :
1131 FileselCaller->gdata->pixel[DIRCOLOR+b-1]);
1132 XDrawImageString(dpy, Filesel, FileselCaller->gdata->wingc,
1133 d, j, s, strlen(s));
1134 }
1135 }
1136 }
1137
1138 void
PopFilesel(Context)1139 PopFilesel(Context)
1140 struct Sundata * Context;
1141 {
1142 int a, b, w, h, x=0, y=0;
1143
1144 if (do_filesel)
1145 do_filesel = 0;
1146 else
1147 do_filesel = 1;
1148
1149 if (!do_filesel)
1150 {
1151 XDestroyWindow(dpy, Filesel);
1152 Filesel = 0;
1153 FileselCaller = NULL;
1154 if (dirtable) free_dirlist(dirtable);
1155 dirtable = NULL;
1156 return;
1157 }
1158
1159 if (!Filesel)
1160 Filesel = newWindow(NULL, &FileselGeom, 3);
1161
1162 XSelectInput(dpy, Filesel, 0);
1163 FileselCaller = Context;
1164 filesel_shift = 0;
1165
1166 if (!getPlacement(Context->win, &Context->geom.x,
1167 &Context->geom.y, &w, &h)) {
1168 x = Context->geom.x + FileselGeom.x - horiz_drift - 5;
1169 a = Context->geom.y + h + 6;
1170 if (do_menu && Context == MenuCaller)
1171 a += MenuGeom.height + MenuGeom.y + vert_drift + 2;
1172 b = Context->geom.y - FileselGeom.height - FileselGeom.y - 2*vert_drift - 28;
1173 if (b < TOPTITLEBARHEIGHT ) b = TOPTITLEBARHEIGHT;
1174 if (a > (int) DisplayHeight(dpy,scr)
1175 - FileselGeom.height - vert_drift - 20)
1176 a = b;
1177 y = (placement<=NE)? a : b;
1178 }
1179
1180 setSizeHints(NULL, 3);
1181 XMoveWindow(dpy, Filesel, x, y);
1182 XMapRaised(dpy, Filesel);
1183 XMoveWindow(dpy, Filesel, x, y);
1184 XFlush(dpy);
1185 usleep(2*TIMESTEP);
1186 setupFilesel(-1);
1187 setProtocols(NULL, 3);
1188 }
1189
1190 void
processFileselAction(Context,x,y,evtype)1191 processFileselAction(Context, x, y, evtype)
1192 struct Sundata * Context;
1193 int x;
1194 int y;
1195 int evtype;
1196 {
1197 static int pressed3 = 0;
1198 static int move_pos = -1;
1199 static int click_pos = -1;
1200 static int but_pos;
1201 char newdir[1030];
1202 char *s, *f, *path;
1203
1204 if (evtype == MotionNotify && move_pos>=0) {
1205 drawButton(Filesel, move_pos, -2);
1206 move_pos = -1;
1207 }
1208 if (evtype == ButtonRelease && click_pos>=0) {
1209 drawButton(Filesel, click_pos, 0);
1210 click_pos = -1;
1211 }
1212
1213 but_pos = getButton(Filesel, x, y);
1214
1215 if (evtype == ButtonPress) {
1216 if (click_pos>=0) drawButton(Filesel, click_pos, 0);
1217 if (but_pos>=0) drawButton(Filesel, but_pos, 1);
1218 click_pos = but_pos;
1219 pressed3 = 1;
1220 return;
1221 }
1222 if (evtype == ButtonRelease) {
1223 pressed3 = 0;
1224 }
1225
1226 if (evtype == MotionNotify) {
1227 if (but_pos>=0 && but_pos!=click_pos) {
1228 drawButton(Filesel, but_pos, -1);
1229 move_pos = but_pos;
1230 }
1231 if (x < FileselGeom.width - 15 ||
1232 y <= 2 * Context->gdata->menustrip)
1233 return;
1234 }
1235
1236 if (y <= Context->gdata->menustrip) {
1237 if (but_pos==0 && getenv("HOME"))
1238 sprintf(image_dir, "%s/", getenv("HOME"));
1239 if (but_pos==1)
1240 StringReAlloc(&image_dir, share_maps_dir);
1241 if (but_pos==2)
1242 StringReAlloc(&image_dir, "/");
1243 if (but_pos==3 && getcwd(NULL,1024)) {
1244 sprintf(newdir, "%s/", getcwd(NULL,1024));
1245 StringReAlloc(&image_dir, newdir);
1246 }
1247 if (but_pos>=0 && but_pos<=3) {
1248 filesel_shift = 0;
1249 if (dirtable) {
1250 free(dirtable);
1251 dirtable = NULL;
1252 }
1253 }
1254 if (but_pos==4) {
1255 do_filesel = -1;
1256 processKey(Context->win, XK_w);
1257 return;
1258 }
1259 if (but_pos==5) {
1260 processKey(Context->win, XK_exclam);
1261 return;
1262 }
1263 if (but_pos>=6) {
1264 XUnmapWindow(dpy, Filesel);
1265 do_filesel = 0;
1266 return;
1267 }
1268 setupFilesel(0);
1269 return;
1270 }
1271 if (y <= 2*Context->gdata->menustrip) {
1272 filesel_shift = 0;
1273 setupFilesel(0);
1274 return;
1275 }
1276
1277 if (x > FileselGeom.width - 15) {
1278 int old_shift = filesel_shift;
1279 if (y <= 2*Context->gdata->menustrip + 10) {
1280 if (evtype != ButtonRelease) return;
1281 if (filesel_shift == 0) return;
1282 filesel_shift -= num_lines/2;
1283 if (filesel_shift <0) filesel_shift = 0;
1284 } else
1285 if (y >= FileselGeom.height - 10) {
1286 if (evtype != ButtonRelease) return;
1287 if (num_table_entries-filesel_shift<num_lines) return;
1288 filesel_shift += num_lines/2;
1289 } else {
1290 if (evtype == MotionNotify && !pressed3) {
1291 return;
1292 }
1293 filesel_shift = ( num_table_entries *
1294 ( y - 2*Context->gdata->menustrip - 10 ))
1295 / (FileselGeom.height - 2*Context->gdata->menustrip - 20);
1296 if (filesel_shift > num_table_entries - num_lines/2)
1297 filesel_shift = num_table_entries - num_lines/2;
1298 if (filesel_shift < 0) filesel_shift = 0;
1299 }
1300 if (filesel_shift != old_shift)
1301 setupFilesel(1);
1302 return;
1303 }
1304
1305 y = (y-2*Context->gdata->menustrip-4)/(3*Context->gdata->menustrip/4)
1306 +filesel_shift;
1307 if (y<num_table_entries) {
1308 s = dirtable[y];
1309 if (s==NULL || *s=='\0') return;
1310 if (x > XTextWidth (Context->gdata->font[MENUFONT], s,
1311 strlen(s))+Context->gdata->charspace/4) return;
1312 y = strlen(s)-1;
1313 f = (char *) salloc(strlen(image_dir)+y+2);
1314 strcpy(f, image_dir);
1315 if (s[y] == '/') {
1316 int l;
1317 if (!strcmp(s, "../")) {
1318 l=strlen(f)-1;
1319 if (l==0) return;
1320 f[l--] = '\0';
1321 while (l>=0 && f[l] != '/')
1322 f[l--] = '\0';
1323 s = "";
1324 }
1325 strcat(f, s);
1326 l=strlen(f);
1327 if (f[l-1] != '/') {
1328 f[l] = 'l';
1329 f[++l] = '\0';
1330 }
1331 if (dirtable) free_dirlist(dirtable);
1332 dirtable = NULL;
1333 filesel_shift = 0;
1334 num_table_entries=0;
1335 StringReAlloc(&image_dir, f);
1336 free(f);
1337 setupFilesel(0);
1338 return;
1339 } else {
1340 path = (Context->wintype)?
1341 Context->map_img_file : Context->clock_img_file;
1342 f = (char *)
1343 salloc((strlen(image_dir)+strlen(s)+2)*sizeof(char));
1344 sprintf(f, "%s%s", image_dir, s);
1345 if (!path || strcmp(f, path)) {
1346 if (Context->wintype)
1347 StringReAlloc(&Context->map_img_file, f);
1348 else
1349 StringReAlloc(&Context->clock_img_file, f);
1350 setupFilesel(3);
1351 adjustGeom(Context, 0);
1352 shutDown(Context, 0);
1353 buildMap(Context, Context->wintype, 0);
1354 }
1355 free(f);
1356 }
1357 }
1358 }
1359
1360 void
checkZoomSettings(zoom)1361 checkZoomSettings(zoom)
1362 ZoomSettings *zoom;
1363 {
1364 if (zoom->fx<1.0) zoom->fx = 1.0;
1365 if (zoom->fx>100.0) zoom->fx = 100.0;
1366
1367 if (zoom->fy<1.0) zoom->fy = 1.0;
1368 if (zoom->fy>100.0) zoom->fy = 100.0;
1369
1370 if (zoom->fdx<0.0) zoom->fdx = 0.0;
1371 if (zoom->fdx>1.0) zoom->fdx = 1.0;
1372
1373 if (zoom->fdy<0.01) zoom->fdy = 0.01;
1374 if (zoom->fdy>0.99) zoom->fdy = 0.99;
1375 }
1376
setZoomAspect(Context,mode)1377 int setZoomAspect(Context, mode)
1378 struct Sundata * Context;
1379 int mode;
1380 {
1381 double a, b, f, p;
1382 int change;
1383
1384 checkZoomSettings(&Context->newzoom);
1385
1386 if (memcmp(&Context->newzoom, &Context->zoom, sizeof(ZoomSettings)))
1387 Context->oldzoom = Context->zoom;
1388
1389 if (!Context->newzoom.mode) return 0;
1390
1391 a = Context->newzoom.fx;
1392 b = Context->newzoom.fy;
1393 change = 0;
1394
1395 if (Context->newzoom.mode == 1)
1396 f = 1.0;
1397 else
1398 f = (double)Context->geom.width /
1399 ((double)Context->geom.height *2.0 * sin(M_PI*Context->newzoom.fdy));
1400
1401 if (mode == 3) {
1402 p = sqrt( Context->newzoom.fx * Context->newzoom.fy / f);
1403 Context->newzoom.fx = p;
1404 Context->newzoom.fy = p * f;
1405 f = 0;
1406 mode = 1;
1407 }
1408
1409 if (mode == 1) {
1410 if (f == 0)
1411 mode = 2;
1412 else
1413 Context->newzoom.fx = Context->newzoom.fy / f;
1414 if (Context->newzoom.fx < 1.0) {
1415 Context->newzoom.fy = Context->newzoom.fy / Context->newzoom.fx;
1416 Context->newzoom.fx = 1.0;
1417 }
1418 if (Context->newzoom.fx > 100.0) {
1419 Context->newzoom.fy = 100.0 * Context->newzoom.fy / Context->newzoom.fx;
1420 Context->newzoom.fx = 100.0;
1421 }
1422 }
1423
1424 if (mode == 2) {
1425 if (f!=0)
1426 Context->newzoom.fy = Context->newzoom.fx * f;
1427 if (Context->newzoom.fy < 1.0) {
1428 Context->newzoom.fx = Context->newzoom.fx / Context->newzoom.fy;
1429 Context->newzoom.fy = 1.0;
1430 }
1431 if (Context->newzoom.fy > 100.0) {
1432 Context->newzoom.fx = 100.0 * Context->newzoom.fx / Context->newzoom.fy;
1433 Context->newzoom.fy = 100.0;
1434 }
1435 }
1436
1437 if (fabs(a-Context->newzoom.fx) > 1E-4) {
1438 zoom_mode |= 10;
1439 change = 1;
1440 } else
1441 Context->newzoom.fx = a;
1442
1443 if (fabs(b-Context->newzoom.fy) > 1E-4) {
1444 zoom_mode |= 12;
1445 change = 1;
1446 } else
1447 Context->newzoom.fy = b;
1448
1449 if (verbose && change)
1450 fprintf(stderr, "Adjusting zoom area aspect (%.2f , %.2f) --> "
1451 "(%.2f , %.2f)\n", a, b, Context->newzoom.fx , Context->newzoom.fy);
1452
1453 return change;
1454 }
1455
1456 void
setZoomDimension(Context)1457 setZoomDimension(Context)
1458 struct Sundata * Context;
1459 {
1460 double rx, ry;
1461
1462 setZoomAspect(Context, 3);
1463
1464 Context->newzoom.width = (int)
1465 ((double) Context->geom.width * Context->newzoom.fx + 0.25);
1466 Context->newzoom.height = (int)
1467 ((double) Context->geom.height * Context->newzoom.fy + 0.25);
1468
1469 rx = 0.5/Context->newzoom.fx;
1470 ry = 0.5/Context->newzoom.fy;
1471 Context->newzoom.dx = (int)
1472 ((double) Context->newzoom.width * (Context->newzoom.fdx-rx) + 0.25);
1473 Context->newzoom.dy = (int)
1474 ((double) Context->newzoom.height * (Context->newzoom.fdy-ry) + 0.25);
1475
1476 if (Context->newzoom.dx < 0) Context->newzoom.dx = 0;
1477 if (Context->newzoom.dy < 0) Context->newzoom.dy = 0;
1478 if (Context->newzoom.dx+Context->geom.width>Context->newzoom.width)
1479 Context->newzoom.dx = Context->newzoom.width - Context->geom.width;
1480 if (Context->newzoom.dy+Context->geom.height>Context->newzoom.height)
1481 Context->newzoom.dy = Context->newzoom.height - Context->geom.height;
1482
1483 if (verbose && !button_pressed)
1484 fprintf(stderr, "Zoom (%.2f, %.2f) centering at (%.2f, %.2f)\n",
1485 Context->newzoom.fx, Context->newzoom.fy,
1486 Context->newzoom.fdx, Context->newzoom.fdy);
1487 }
1488
1489 void
showZoomHint(but_pos)1490 showZoomHint(but_pos)
1491 int but_pos;
1492 {
1493 static int move_pos = -1;
1494 char hint[120];
1495 int v;
1496
1497 if (move_pos>=0) drawButton(Zoom, move_pos, -2);
1498 if (but_pos>=0) drawButton(Zoom, but_pos, -1);
1499 move_pos = but_pos;
1500
1501 if (!do_zoom || zoom_lasthint==zoom_newhint) return;
1502
1503 zoom_lasthint = zoom_newhint;
1504 v = ZoomGeom.height - ZoomCaller->gdata->menustrip;
1505
1506 if (zoom_newhint=='\033')
1507 strcpy(hint, Label[L_ESCMENU]);
1508 else
1509 if (zoom_newhint==' ')
1510 sprintf(hint,
1511 "magx = %.3f, magy = %.3f, lon = %.3f�, lat = %.3f�",
1512 ZoomCaller->newzoom.fx, ZoomCaller->newzoom.fy,
1513 360.0 * ZoomCaller->newzoom.fdx - 180.0,
1514 90.0 - ZoomCaller->newzoom.fdy*180.0);
1515 else
1516 strcpy(hint, Help[getNumCmd(zoom_newhint)]);
1517
1518 BasicSettings(ZoomCaller);
1519 XSetWindowBackground(dpy, Zoom, ZoomCaller->gdata->pixel[MENUBGCOLOR]);
1520 XClearArea(dpy, Zoom, 0, v+1, ZoomGeom.width,
1521 ZoomCaller->gdata->menustrip-1, False);
1522 XDrawImageString(dpy, Zoom, ZoomCaller->gdata->wingc, 4,
1523 v + ZoomCaller->gdata->font[MENUFONT]->max_bounds.ascent + 3,
1524 hint, strlen(hint));
1525 }
1526
1527 void
1528 PopZoom();
1529
1530 void
setupZoom(mode)1531 setupZoom(mode)
1532 int mode;
1533 {
1534 int i, j, k;
1535 int zoomx, zoomy, zoomw, zoomh;
1536 char *num[] = { "1", "2", "5", "10", "20", "50", "100"};
1537 char *synchro = Label[L_SYNCHRO];
1538 char s[80];
1539
1540 if (!do_zoom) return;
1541
1542 BasicSettings(ZoomCaller);
1543 XSetWindowColormap(dpy, Zoom, ZoomCaller->gdata->cmap);
1544 XSetWindowBackground(dpy, Zoom, ZoomCaller->gdata->pixel[MENUBGCOLOR]);
1545
1546 areaw = ZoomGeom.width - 74;
1547 areah = ZoomGeom.height - 2*ZoomCaller->gdata->menustrip - 65;
1548
1549 if (mode == -1) {
1550 XClearArea(dpy, Zoom, 0,0, ZoomGeom.width, ZoomGeom.height, False);
1551 XDrawImageString(dpy, Zoom, ZoomCaller->gdata->wingc,
1552 160-XTextWidth(ZoomCaller->gdata->font[MENUFONT],
1553 synchro, strlen(synchro))+areah,
1554 24+ ZoomCaller->gdata->font[MENUFONT]->max_bounds.ascent,
1555 synchro, strlen(synchro));
1556
1557 for (i=0; i<=N_ZOOM; i++)
1558 drawButton(Zoom, i, 0);
1559
1560 BasicSettings(ZoomCaller);
1561
1562 for (i=0; i<=6; i++) {
1563 j = 63 + (int) ( (areah-6)*log(atof(num[i]))/log(100.0));
1564 k = j - ZoomCaller->gdata->charspace*strlen(num[i])/10;
1565 XDrawImageString(dpy, Zoom, ZoomCaller->gdata->wingc, k,
1566 ZoomCaller->gdata->font[MENUFONT]->max_bounds.ascent + 3,
1567 num[i], strlen(num[i]));
1568 k = j + ZoomCaller->gdata->font[MENUFONT]->max_bounds.ascent/2 - 10;
1569 XDrawImageString(dpy, Zoom, ZoomCaller->gdata->wingc,
1570 24-ZoomCaller->gdata->charspace*strlen(num[i])/4, k ,
1571 num[i], strlen(num[i]));
1572 XDrawLine(dpy, Zoom, ZoomCaller->gdata->wingc, j, 20, j, 24);
1573 XDrawLine(dpy, Zoom, ZoomCaller->gdata->wingc, 30, j-10, 34, j-10);
1574 }
1575
1576 XDrawLine(dpy, Zoom, ZoomCaller->gdata->wingc, 60, 22, areah+60, 22);
1577 XDrawLine(dpy, Zoom, ZoomCaller->gdata->wingc, 32, 50, 32, areah+50);
1578 }
1579
1580 XSetWindowBackground(dpy, Zoom, ZoomCaller->gdata->pixel[ZOOMBGCOLOR]);
1581 if ((mode & 1) && !ZoomCaller->newzoom.mode)
1582 XClearArea(dpy, Zoom, 41, 31, 9, 9, False);
1583 if (mode & 2)
1584 XClearArea(dpy, Zoom, 61, 31, areah, 9, False);
1585 if (mode & 4)
1586 XClearArea(dpy, Zoom, 41, 51, 9, areah, False);
1587
1588 if (!zoompix) {
1589 int oldlevel, oldfill, code, num;
1590
1591 oldlevel = ZoomCaller->flags.colorlevel;
1592 oldfill = ZoomCaller->flags.fillmode;
1593 ZoomCaller->flags.colorlevel = MONOCHROME;
1594 ZoomCaller->flags.fillmode = 1;
1595 i = ZoomCaller->geom.width;
1596 j = ZoomCaller->geom.height;
1597 ZoomCaller->newzoom = ZoomCaller->zoom;
1598 ZoomCaller->zoom.width = ZoomCaller->geom.width = areaw;
1599 ZoomCaller->zoom.height = ZoomCaller->geom.height = areah;
1600 ZoomCaller->zoom.dx = ZoomCaller->zoom.dy = 0;
1601
1602 code = readVMF(Zoom_img_file, ZoomCaller);
1603 if (code) {
1604 if (ZoomCaller->bits) free(ZoomCaller->bits);
1605 ZoomCaller->bits = NULL;
1606 }
1607 if (!ZoomCaller->bits) {
1608 num = ((ZoomCaller->geom.width+7)/8)*
1609 ZoomCaller->geom.height*sizeof(char);
1610 ZoomCaller->bits = (char *) salloc(num);
1611 }
1612 if (code && ZoomCaller->bits)
1613 memset(ZoomCaller->bits, 0xFF, num);
1614 if (ZoomCaller->bits) {
1615 zoompix = XCreatePixmapFromBitmapData(dpy, Root,
1616 ZoomCaller->bits, ZoomCaller->geom.width,
1617 ZoomCaller->geom.height, 0, 1, 1);
1618 free(ZoomCaller->bits);
1619 }
1620
1621 ZoomCaller->zoom = ZoomCaller->newzoom;
1622 ZoomCaller->geom.width = i;
1623 ZoomCaller->geom.height = j;
1624 ZoomCaller->flags.colorlevel = oldlevel;
1625 ZoomCaller->flags.fillmode = oldfill;
1626 }
1627
1628 XSetWindowBackground(dpy, Zoom, ZoomCaller->gdata->pixel[CHOICECOLOR]);
1629 XSetBackground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[CHOICECOLOR]);
1630 XSetForeground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[CHANGECOLOR]);
1631
1632 if (mode & 2) {
1633 i = (int) ( (double)(areah-6)*log(ZoomCaller->zoom.fx)/log(100.00));
1634 XClearArea(dpy, Zoom, 61+i, 31, 6, 9, False);
1635 if (ZoomCaller->newzoom.fx != ZoomCaller->zoom.fx) {
1636 i = (int) ((double)(areah-6)*log(ZoomCaller->newzoom.fx)/log(100.00));
1637 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, 61+i, 31, 5, 8);
1638 }
1639 }
1640 if (mode & 4) {
1641 j = (int) ( (double)(areah-6)*log(ZoomCaller->zoom.fy)/log(100.0));
1642 XClearArea(dpy, Zoom, 41, 51+j, 9, 6, False);
1643 if (ZoomCaller->newzoom.fy != ZoomCaller->zoom.fy) {
1644 j = (int) ((double)(areah-6)*log(ZoomCaller->newzoom.fy)/log(100.0));
1645 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, 41, 51+j, 8, 5);
1646 }
1647 }
1648
1649 if (mode & 8) {
1650 zoomw = (areaw*ZoomCaller->geom.width)/ZoomCaller->zoom.width;
1651 zoomh = (areah*ZoomCaller->geom.height)/ZoomCaller->zoom.height;
1652 zoomx = (areaw*ZoomCaller->zoom.dx)/ZoomCaller->zoom.width;
1653 zoomy = (areah*ZoomCaller->zoom.dy)/ZoomCaller->zoom.height;
1654 i = areaw-zoomx-zoomw-1;
1655 j = areah-zoomy-zoomh-1;
1656
1657 XSetBackground(dpy, ZoomCaller->gdata->wingc,
1658 ZoomCaller->gdata->pixel[ZOOMBGCOLOR]);
1659 XSetForeground(dpy, ZoomCaller->gdata->wingc,
1660 ZoomCaller->gdata->pixel[ZOOMFGCOLOR]);
1661
1662 if (zoomy)
1663 XCopyPlane(dpy, zoompix, Zoom, ZoomCaller->gdata->wingc,
1664 0, 0, areaw-1, zoomy, 61, 51, 1);
1665 if (j>0)
1666 XCopyPlane(dpy, zoompix, Zoom, ZoomCaller->gdata->wingc,
1667 0, zoomy+zoomh+1, areaw, j, 61, 52+zoomy+zoomh, 1);
1668 if (zoomx)
1669 XCopyPlane(dpy, zoompix, Zoom, ZoomCaller->gdata->wingc,
1670 0, 0, zoomx, areah-1, 61, 51, 1);
1671 if (i>0)
1672 XCopyPlane(dpy, zoompix, Zoom, ZoomCaller->gdata->wingc,
1673 zoomx+zoomw+1, 0, i, areah, 62+zoomx+zoomw, 51, 1);
1674
1675 if (ZoomCaller->flags.colorlevel == MONOCHROME) {
1676 XSetBackground(dpy, ZoomCaller->gdata->wingc,
1677 ZoomCaller->gdata->pixel[ZOOMFGCOLOR]);
1678 XSetForeground(dpy, ZoomCaller->gdata->wingc,
1679 ZoomCaller->gdata->pixel[ZOOMBGCOLOR]);
1680 } else
1681 XSetBackground(dpy, ZoomCaller->gdata->wingc,
1682 ZoomCaller->gdata->pixel[CHOICECOLOR]);
1683
1684 XCopyPlane(dpy, zoompix, Zoom, ZoomCaller->gdata->wingc,
1685 zoomx, zoomy, zoomw+1, zoomh+1, 61+zoomx, 51+zoomy, 1);
1686
1687 if (ZoomCaller->newzoom.fx!=ZoomCaller->zoom.fx ||
1688 ZoomCaller->newzoom.fy!=ZoomCaller->zoom.fy ||
1689 ZoomCaller->newzoom.fdx!=ZoomCaller->zoom.fdx ||
1690 ZoomCaller->newzoom.fdy!=ZoomCaller->zoom.fdy) {
1691 zoomw = (areaw*ZoomCaller->geom.width)/ZoomCaller->newzoom.width;
1692 zoomh = (areah*ZoomCaller->geom.height)/ZoomCaller->newzoom.height;
1693 zoomx = (areaw*ZoomCaller->newzoom.dx)/ZoomCaller->newzoom.width;
1694 zoomy = (areah*ZoomCaller->newzoom.dy)/ZoomCaller->newzoom.height;
1695 if (ZoomCaller->flags.colorlevel==MONOCHROME)
1696 drawDottedRectangle(dpy, Zoom, ZoomCaller->gdata->wingc,
1697 61+zoomx, 51+zoomy, zoomw, zoomh,
1698 ZoomCaller->gdata->pixel[ZOOMFGCOLOR],
1699 ZoomCaller->gdata->pixel[ZOOMBGCOLOR]);
1700 else {
1701 XSetForeground(dpy, ZoomCaller->gdata->wingc,
1702 ZoomCaller->gdata->pixel[CHANGECOLOR]);
1703 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc,
1704 61+zoomx, 51+zoomy, zoomw, zoomh);
1705 }
1706 }
1707
1708 i = 60 + (int) (areaw * ZoomCaller->newzoom.fdx);
1709 j = 50 + (int) (areah * ZoomCaller->newzoom.fdy);
1710
1711 XSetForeground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[CHANGECOLOR]);
1712 if (i<60+areaw && j<50+areah)
1713 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, i, j, 1, 1);
1714
1715 XSetForeground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[MENUFGCOLOR]);
1716 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, 60, 50, areaw+1, areah+1);
1717 }
1718
1719 XSetWindowBackground(dpy, Zoom, ZoomCaller->gdata->pixel[MENUBGCOLOR]);
1720 XSetBackground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[MENUBGCOLOR]);
1721 XSetForeground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[MENUFGCOLOR]);
1722
1723 if (mode & 1) {
1724 XClearArea(dpy, Zoom, 33, 23, 17, 17, False);
1725 s[0] = '0'+ZoomCaller->newzoom.mode;
1726 s[1] = '\0';
1727 XDrawImageString(dpy, Zoom, ZoomCaller->gdata->wingc,
1728 39, 25+ZoomCaller->gdata->font[MENUFONT]->max_bounds.ascent, s, 1);
1729 }
1730
1731 if (mode & 16) {
1732 drawButton(Zoom, N_ZOOM+1, 0);
1733 }
1734
1735 XSetForeground(dpy, ZoomCaller->gdata->wingc, ZoomCaller->gdata->pixel[MENUFGCOLOR]);
1736
1737 if (mode == -1) {
1738 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, 60, 30, areah+1, 10);
1739 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, 40, 50, 10, areah+1);
1740 XDrawRectangle(dpy, Zoom, ZoomCaller->gdata->wingc, 32, 22, 18, 18);
1741 drawButton(Zoom, N_ZOOM+1, 0);
1742 }
1743
1744 zoom_lasthint = '\0';
1745 showZoomHint(-1);
1746 }
1747
1748 void
PopZoom(Context)1749 PopZoom(Context)
1750 struct Sundata * Context;
1751 {
1752 int a, b, w, h, x=0, y=0;
1753
1754 if (do_zoom) {
1755 XDestroyWindow(dpy, Zoom);
1756 Zoom = 0;
1757 ZoomCaller = NULL;
1758 zoom_active = 1;
1759 do_zoom = 0;
1760 if (zoompix) {
1761 XFreePixmap(dpy, zoompix);
1762 zoompix = 0;
1763 }
1764 return;
1765 } else
1766 do_zoom = 1;
1767
1768 if (!Zoom)
1769 Zoom = newWindow(NULL, &ZoomGeom, 4);
1770
1771 Context->newzoom = Context->zoom;
1772 XSelectInput(dpy, Zoom, 0);
1773
1774 ZoomCaller = Context;
1775 zoom_shift = 0;
1776 zoom_mode = 0;
1777 zoom_active = do_zoomsync;
1778 zoom_newhint = ' ';
1779
1780 if (!getPlacement(Context->win, &Context->geom.x, &Context->geom.y, &w, &h)) {
1781 x = Context->geom.x + ZoomGeom.x - horiz_drift - 5;
1782 a = Context->geom.y + h + 6;
1783 if (do_menu && Context == MenuCaller)
1784 a += MenuGeom.height + MenuGeom.y + vert_drift + 2;
1785 b = Context->geom.y - ZoomGeom.height - ZoomGeom.y - 2*vert_drift - 28;
1786 if (b < TOPTITLEBARHEIGHT ) b = TOPTITLEBARHEIGHT;
1787 if (a > (int) DisplayHeight(dpy,scr)
1788 - ZoomGeom.height - vert_drift -20)
1789 a = b;
1790 y = (placement<=NE)? a : b;
1791 }
1792
1793 setSizeHints(NULL, 4);
1794 XMoveWindow(dpy, Zoom, x, y);
1795 XMapRaised(dpy, Zoom);
1796 XMoveWindow(dpy, Zoom, x, y);
1797 XFlush(dpy);
1798 usleep(2*TIMESTEP);
1799 option_lasthint = '\0';
1800 setupZoom(-1);
1801 setProtocols(NULL, 4);
1802 }
1803
1804 void
activateZoom(Context,rebuild)1805 activateZoom(Context, rebuild)
1806 Sundata *Context;
1807 int rebuild;
1808 {
1809 setZoomDimension(Context);
1810 zoom_newhint = ' ';
1811 setupZoom(zoom_mode);
1812 if (rebuild) {
1813 if (Context->zoom.width!=Context->newzoom.width ||
1814 Context->zoom.height!=Context->newzoom.height ||
1815 Context->zoom.dx!=Context->newzoom.dx ||
1816 Context->zoom.dy!=Context->newzoom.dy) {
1817 Context->zoom = Context->newzoom;
1818 shutDown(Context, 0);
1819 buildMap(Context, Context->wintype, 0);
1820 zoom_newhint = ' ';
1821 setupZoom(zoom_mode);
1822 } else
1823 Context->zoom = Context->newzoom;
1824 }
1825 if (rebuild>0)
1826 zoom_mode = 0;
1827 }
1828
processZoomAction(Context,x,y,button,evtype)1829 void processZoomAction(Context, x, y, button, evtype)
1830 Sundata * Context;
1831 int x;
1832 int y;
1833 int button;
1834 int evtype;
1835 {
1836 static int click_pos=-1;
1837 double v1, v2;
1838 int but_pos;
1839
1840 if (evtype == ButtonRelease && click_pos>=0) {
1841 drawButton(Zoom, click_pos, 0);
1842 click_pos = -1;
1843 }
1844
1845 if (y>areah+63 && y<areah+63+Context->gdata->menustrip) {
1846 but_pos = getButton(Zoom, x, y);
1847 if (but_pos>=N_ZOOM)
1848 zoom_newhint = '\033';
1849 else
1850 if (but_pos>=0)
1851 zoom_newhint = ZoomKey[2*but_pos];
1852 if (evtype==MotionNotify) {
1853 if (but_pos>=0)
1854 showZoomHint(but_pos);
1855 }
1856 if (evtype==ButtonPress && but_pos>=0) {
1857 drawButton(Zoom, but_pos, 1);
1858 click_pos = but_pos;
1859 }
1860 if (evtype==ButtonRelease) {
1861 if (zoom_newhint == '\033') {
1862 PopZoom(Context);
1863 return;
1864 }
1865 if (zoom_newhint == 'W') do_zoom = -1;
1866 processKey(Context->win, tolower(zoom_newhint));
1867 showZoomHint(but_pos);
1868 zoom_mode = 0;
1869 }
1870 return;
1871 }
1872 if (button_pressed>=2) return;
1873
1874 if (evtype==ButtonRelease)
1875 drawButton(Zoom, N_ZOOM+1, 0);
1876 if (evtype==MotionNotify)
1877 drawButton(Zoom, N_ZOOM+1, -2);
1878
1879 if (x>areah+170 && x<areah+170+Context->gdata->charspace &&
1880 y>21 && y<39) {
1881 if (evtype==MotionNotify) {
1882 drawButton(Zoom, N_ZOOM+1, -1);
1883 zoom_newhint = '"';
1884 showZoomHint(getNumCmd(zoom_newhint));
1885 }
1886 if (evtype==ButtonPress) {
1887 drawButton(Zoom, N_ZOOM+1, 1);
1888 }
1889 if (evtype==ButtonRelease) {
1890 zoom_active = 1 -zoom_active;
1891 zoom_mode |= 16;
1892 }
1893 } else
1894 if (x>=60 && x<=areah+60 && y>=30 && y<=40 && button_pressed) {
1895 v1 = exp((double)(x-66)*log(100.00)/(double)(areah-6));
1896 if (v1 != Context->newzoom.fx) {
1897 Context->newzoom.fx = v1;
1898 zoom_mode |= 10;
1899 (void) setZoomAspect(Context, 2);
1900 }
1901 } else
1902 if (x>=40 && x<=50 && y>=50 && y<=areah+50 && button_pressed) {
1903 v2 = exp((double)(y-53)*log(100.00)/(double)(areah-6));
1904 if (v2 != Context->newzoom.fy) {
1905 Context->newzoom.fy = v2;
1906 zoom_mode |= 12;
1907 (void) setZoomAspect(Context, 1);
1908 }
1909 }
1910 else
1911 if (x>=60 && y>=50 && x<=60+areaw && y<=50+areah && button_pressed){
1912 v1 = ((double)(x-60))/((double)areaw);
1913 v2 = ((double)(y-50))/((double)areah);
1914 if (v1!=Context->newzoom.fdx || v2!=Context->newzoom.fdy) {
1915 Context->newzoom.fdx = v1;
1916 Context->newzoom.fdy = v2;
1917 zoom_mode |= 8;
1918 }
1919 (void) setZoomAspect(Context, 3);
1920 }
1921 else {
1922 zoom_newhint = ' ';
1923 showZoomHint(-1);
1924 if (button_pressed) return;
1925 }
1926
1927 if (zoom_mode>0) {
1928 setZoomDimension(Context);
1929 if (zoom_active && !button_pressed &&
1930 memcmp(&Context->newzoom,
1931 &Context->zoom, sizeof(ZoomSettings))) {
1932 button_pressed = 0;
1933 activateZoom(Context, -1);
1934 } else
1935 setupZoom(zoom_mode);
1936 if (!button_pressed) zoom_mode = 0;
1937 }
1938 }
1939
1940 void
showOptionHint(but_pos)1941 showOptionHint(but_pos)
1942 int but_pos;
1943 {
1944 static int move_pos = -1;
1945 char hint[128];
1946 int l, v;
1947
1948 if (move_pos>=0) drawButton(Option, move_pos, -2);
1949 if (but_pos>=0) drawButton(Option, but_pos, -1);
1950 move_pos = but_pos;
1951
1952 if (!do_option || option_lasthint==option_newhint) return;
1953
1954 *hint = '\0';
1955
1956 option_lasthint = option_newhint;
1957 v = OptionGeom.height - OptionCaller->gdata->menustrip;
1958
1959 if (option_newhint=='\033')
1960 strcpy(hint, Label[L_ESCMENU]);
1961 else
1962 if (option_newhint==' ')
1963 strcpy(hint, Label[L_OPTIONINTRO]);
1964 else
1965 if (option_newhint=='\n')
1966 strcpy(hint, Label[L_ACTIVATE]);
1967 else
1968 if (option_newhint=='?')
1969 strcpy(hint, Label[L_INCORRECT]);
1970 else {
1971 if (option_newhint == 'G' || option_newhint == 'J')
1972 option_lasthint = ' ';
1973 helpHint(OptionCaller, option_newhint, hint);
1974 }
1975
1976 l = strlen(hint);
1977
1978 BasicSettings(OptionCaller);
1979 XSetWindowBackground(dpy, Option, OptionCaller->gdata->pixel[MENUBGCOLOR]);
1980
1981 XClearArea(dpy, Option, 0, v+1, OptionGeom.width,
1982 OptionCaller->gdata->menustrip-1, False);
1983
1984 XDrawImageString(dpy, Option, OptionCaller->gdata->wingc,
1985 4, v + OptionCaller->gdata->font[MENUFONT]->max_bounds.ascent + 3,
1986 hint, l);
1987 }
1988
1989 void
showCaret(Context,win,entry,x,y,mode)1990 showCaret(Context, win, entry, x, y, mode)
1991 Sundata * Context;
1992 Window win;
1993 TextEntry *entry;
1994 int x, y, mode;
1995 {
1996 int i, j;
1997
1998 i = XTextWidth(Context->gdata->font[MENUFONT], entry->string, entry->caret);
1999 j = XTextWidth(Context->gdata->font[MENUFONT], "_", 1);
2000
2001 XSetWindowBackground(dpy, win,
2002 Context->gdata->pixel[(mode)? CARETCOLOR : OPTIONBGCOLOR]);
2003 XClearArea(dpy, win,
2004 x+i, y+Context->gdata->font[MENUFONT]->max_bounds.ascent+
2005 Context->gdata->menustrip/3 - 1, j, 2, False);
2006 }
2007
2008 void
setupOption(mode)2009 setupOption(mode)
2010 int mode;
2011 {
2012 int i, vskip;
2013 char s[80];
2014
2015 if (!do_option) return;
2016
2017 BasicSettings(OptionCaller);
2018 XSetWindowColormap(dpy, Option, OptionCaller->gdata->cmap);
2019 XSetWindowBackground(dpy, Option, OptionCaller->gdata->pixel[MENUBGCOLOR]);
2020
2021 vskip = 3*OptionCaller->gdata->menustrip/8;
2022 option_lasthint = '\0';
2023
2024 if (mode == -1) {
2025 XClearArea(dpy, Option, 0,0, OptionGeom.width,
2026 OptionGeom.height, False);
2027 for (i=0; i<=N_OPTION; i++)
2028 drawButton(Option, i, 0);
2029
2030 XSetBackground(dpy, OptionCaller->gdata->wingc,
2031 OptionCaller->gdata->pixel[MENUBGCOLOR]);
2032 XSetForeground(dpy, OptionCaller->gdata->wingc,
2033 OptionCaller->gdata->pixel[MENUFGCOLOR]);
2034 strcpy(s, Label[L_OPTION]);
2035 XDrawImageString(dpy, Option, OptionCaller->gdata->wingc,
2036 8, OptionCaller->gdata->font[MENUFONT]->max_bounds.ascent + vskip + 3,
2037 s, strlen(s));
2038 XDrawRectangle(dpy, Option, OptionCaller->gdata->wingc,
2039 70, vskip, OptionGeom.width-85,
2040 OptionCaller->gdata->menustrip);
2041 }
2042
2043 XSetWindowBackground(dpy, Option,
2044 OptionCaller->gdata->pixel[OPTIONBGCOLOR]);
2045 XClearArea(dpy, Option, 71,vskip+1, OptionGeom.width-86,
2046 OptionCaller->gdata->menustrip-1, False);
2047 XSetBackground(dpy, OptionCaller->gdata->wingc,
2048 OptionCaller->gdata->pixel[OPTIONBGCOLOR]);
2049 XSetForeground(dpy, OptionCaller->gdata->wingc,
2050 OptionCaller->gdata->pixel[OPTIONFGCOLOR]);
2051
2052 XDrawImageString(dpy, Option, OptionCaller->gdata->wingc, 76,
2053 OptionCaller->gdata->font[MENUFONT]->max_bounds.ascent + vskip + 3,
2054 option_entry.string, strlen(option_entry.string));
2055 if (text_input == OPTION_INPUT)
2056 showCaret(OptionCaller, Option, &option_entry, 76, vskip, 1);
2057 showOptionHint(-1);
2058 }
2059
2060 void
resetStringLength(max,entry)2061 resetStringLength(max, entry)
2062 int max;
2063 TextEntry * entry;
2064 {
2065 int a;
2066
2067 entry->maxlength = max;
2068
2069 a = (entry->string == NULL);
2070 entry->string = (char *)
2071 realloc(entry->string, (max+2)*sizeof(char));
2072 if (a) {
2073 *entry->string = '\0';
2074 entry->caret = 0;
2075 }
2076 if (entry->caret > max) {
2077 entry->string[max] = '\0';
2078 entry->caret = max;
2079 }
2080 }
2081
2082 void
PopOption(Context)2083 PopOption(Context)
2084 struct Sundata * Context;
2085 {
2086 int w, h, a, b, x=0, y=0;
2087
2088 do_option = 1 - do_option;
2089
2090 if (!do_option)
2091 {
2092 XDestroyWindow(dpy, Option);
2093 Option = 0;
2094 OptionCaller = NULL;
2095 return;
2096 }
2097
2098 if (!Option)
2099 Option = newWindow(NULL, &OptionGeom, 5);
2100
2101 XSelectInput(dpy, Option, 0);
2102 OptionCaller = Context;
2103
2104 w = ((OptionGeom.width-86) /
2105 XTextWidth(OptionCaller->gdata->font[MENUFONT], "_", 1)) - 2;
2106 resetStringLength(w, &option_entry);
2107
2108 if (runlevel>=RUNTIMEOPTION)
2109 option_newhint = '\n';
2110 else
2111 option_newhint = ' ';
2112
2113 OptionGeom.height = OptionGeom.h_mini
2114 = (15 * Context->gdata->menustrip)/4;
2115
2116 if (!getPlacement(Context->win, &Context->geom.x, &Context->geom.y, &w, &h)) {
2117 x = Context->geom.x + OptionGeom.x - horiz_drift - 5;
2118 a = Context->geom.y + h + 6;
2119 if (do_menu && Context == MenuCaller)
2120 a += MenuGeom.height + MenuGeom.y + vert_drift + 2;
2121 b = Context->geom.y - OptionGeom.height - OptionGeom.y - 2*vert_drift - 28;
2122 if (b < TOPTITLEBARHEIGHT ) b = TOPTITLEBARHEIGHT;
2123 if (a > (int) DisplayHeight(dpy,scr)
2124 - 2*OptionGeom.height -vert_drift -20)
2125 a = b;
2126 y = (placement<=NE)? a : b;
2127 }
2128 setSizeHints(NULL, 5);
2129 XMoveWindow(dpy, Option, x, y);
2130 XMapRaised(dpy, Option);
2131 XMoveWindow(dpy, Option, x, y);
2132 XFlush(dpy);
2133 usleep(2*TIMESTEP);
2134 option_lasthint = '\0';
2135 option_newhint = ' ';
2136 setupOption(-1);
2137 setProtocols(NULL, 5);
2138 }
2139
2140 void
activateOption()2141 activateOption()
2142 {
2143 Sundata *Context;
2144 Flags oldflags;
2145 ZoomSettings oldzoom;
2146 int i, size;
2147 short *ptr, *oldptr, *newptr;
2148 double *zptr, *zoldptr, *znewptr;
2149
2150 Context = OptionCaller;
2151
2152 if (!do_option || !Context) return;
2153
2154 oldflags = gflags;
2155 gflags.animate += 2;
2156 oldzoom = gzoom;
2157 runlevel = RUNTIMEOPTION;
2158 i = parseCmdLine(option_entry.string);
2159 correctValues();
2160 if (i>0 || runlevel == FAILEDOPTION) {
2161 option_newhint = '?';
2162 showOptionHint(-1);
2163 return;
2164 } else
2165 option_newhint = '\n';
2166
2167 showOptionHint(-1);
2168 /* Set runlevel=IMAGERECYCLE if previous image/pixmap can be recycled */
2169 if (option_changes<4 && gflags.colorlevel==oldflags.colorlevel &&
2170 gflags.fillmode==oldflags.fillmode) {
2171 runlevel = IMAGERECYCLE;
2172 tmp_cmap = Context->gdata->cmap;
2173 if (gflags.colorlevel<FULLCOLORS) {
2174 clearNightArea(Context);
2175 if (gflags.colorlevel==MONOCHROME) {
2176 drawCities(Context);
2177 drawSunAndMoon(Context);
2178 }
2179 } else {
2180 size = Context->xim->bytes_per_line*Context->xim->height;
2181 memcpy(Context->xim->data, Context->ximdata, size);
2182 }
2183 }
2184 shutDown(Context, 0);
2185 memcpy(Context->spotsizes, city_spotsizes, city_cat*sizeof(int));
2186 memcpy(Context->sizelimits, city_sizelimits, city_cat*sizeof(int));
2187
2188 if (gflags.animate<2)
2189 Context->flags.animate = gflags.animate;
2190 else
2191 gflags.animate -= 2;
2192 ptr = (short *) &gflags;
2193 oldptr = (short *) &oldflags;
2194 newptr = (short *) &Context->flags;
2195 for (i=0; i<sizeof(Flags)/sizeof(short); i++)
2196 if (ptr[i]!=oldptr[i]) newptr[i] = ptr[i];
2197
2198 zptr = (double *) &gzoom;
2199 zoldptr = (double *) &oldzoom;
2200 znewptr = (double *) &Context->zoom;
2201 for (i=0; i<6; i++)
2202 if (zptr[i]!=zoldptr[i]) znewptr[i] = zptr[i];
2203
2204 if (option_changes & 8)
2205 Context->geom = ClockGeom;
2206 if (option_changes & 16)
2207 Context->geom = MapGeom;
2208 if (option_changes & 32)
2209 StringReAlloc(&Context->clock_img_file, Clock_img_file);
2210 if (option_changes & 64)
2211 StringReAlloc(&Context->map_img_file, Map_img_file);
2212 buildMap(Context, Context->wintype, 0);
2213 }
2214
2215 void
processOptionAction(Context,x,y,button,evtype)2216 processOptionAction(Context, x, y, button, evtype)
2217 Sundata * Context;
2218 int x, y, button, evtype;
2219 {
2220 static int click_pos = -1;
2221 int i, opth, vskip, but_pos;
2222 KeySym key;
2223
2224 opth = OptionGeom.height - 2 * Context->gdata->menustrip - 1;
2225 vskip = 3*Context->gdata->menustrip/8;
2226
2227 if (evtype == ButtonRelease && click_pos>=0) {
2228 drawButton(Option, click_pos, 0);
2229 click_pos = -1;
2230 }
2231
2232 if (evtype==ButtonRelease && x>=70 &&
2233 x<=OptionGeom.width-15 &&
2234 y>=vskip && y<=Context->gdata->menustrip+vskip) {
2235 text_input = OPTION_INPUT;
2236 but_pos = (x-76)/XTextWidth(OptionCaller->gdata->font[MENUFONT], "_", 1);
2237 i = strlen(option_entry.string);
2238 if (but_pos<0) but_pos = 0;
2239 if (but_pos>i) but_pos = i;
2240 option_entry.caret = but_pos;
2241 setupOption(0);
2242 return;
2243 }
2244
2245 if (evtype==ButtonRelease && text_input==OPTION_INPUT) {
2246 text_input = NULL_INPUT;
2247 setupOption(0);
2248 }
2249
2250 if (y>opth && y<opth+Context->gdata->menustrip) {
2251 but_pos = getButton(Option, x, y);
2252 if (but_pos>=N_OPTION)
2253 option_newhint = '\033';
2254 else
2255 if (but_pos>=0)
2256 option_newhint = OptionKey[2*but_pos];
2257 if (evtype==MotionNotify) {
2258 if (but_pos>=0)
2259 showOptionHint(but_pos);
2260 }
2261 if (evtype==ButtonPress && but_pos>=0) {
2262 drawButton(Option, but_pos, 1);
2263 click_pos = but_pos;
2264 }
2265 if (evtype==ButtonRelease) {
2266 if (but_pos<0) return;
2267 if (but_pos<N_OPTION) {
2268 key = (KeySym)tolower(option_newhint);
2269 processKey(Option, key);
2270 showOptionHint(but_pos);
2271 } else
2272 PopOption(Context);
2273 }
2274 }
2275 }
2276
2277 void
showUrbanHint(str)2278 showUrbanHint(str)
2279 char * str;
2280 {
2281 char hint[128];
2282 int l, v;
2283
2284 if (!do_urban || urban_lasthint==urban_newhint) return;
2285
2286 *hint = '\0';
2287
2288 urban_lasthint = urban_newhint;
2289 v = UrbanGeom.height - UrbanCaller->gdata->menustrip;
2290
2291 if (urban_newhint=='\033')
2292 strcpy(hint, Label[L_ESCMENU]);
2293 else
2294 if (urban_newhint==' ')
2295 strcpy(hint, Help[getNumCmd('U')]);
2296 else {
2297 if (str)
2298 strncpy(hint, str, 125);
2299 else {
2300 l = getNumCmd(urban_newhint);
2301 if (l>=0 && l<N_HELP) {
2302 strcpy(hint, Help[l]);
2303 }
2304 }
2305 }
2306
2307 l = strlen(hint);
2308
2309 BasicSettings(UrbanCaller);
2310 XSetWindowBackground(dpy, Urban, UrbanCaller->gdata->pixel[MENUBGCOLOR]);
2311
2312 XClearArea(dpy, Urban, 0, v+1, UrbanGeom.width,
2313 UrbanCaller->gdata->menustrip-1, False);
2314 XDrawImageString(dpy, Urban, UrbanCaller->gdata->wingc,
2315 4, v + UrbanCaller->gdata->font[MENUFONT]->max_bounds.ascent + 3,
2316 hint, l);
2317 }
2318
2319 void
updateUrbanEntries(Context,city)2320 updateUrbanEntries(Context, city)
2321 Sundata * Context;
2322 City * city;
2323 {
2324 char *ptr;
2325 int w;
2326
2327 text_input = NULL_INPUT;
2328 if (city == NULL) return;
2329 if (city->name && city!=&Context->pos1) {
2330 w = (urban_w[0]/
2331 XTextWidth(UrbanCaller->gdata->font[MENUFONT],"_",1))-2;
2332 if (strlen(city->name)<w) w = strlen(city->name);
2333 strncpy(urban_entry[0].string, city->name, w);
2334 urban_entry[0].string[w] = '\0';
2335 urban_entry[0].caret = strlen(urban_entry[0].string);
2336 } else {
2337 urban_entry[0].string[0]='\0';
2338 urban_entry[0].caret = 0;
2339 }
2340 if (city->tz) {
2341 w = (urban_w[1]/
2342 XTextWidth(UrbanCaller->gdata->font[MENUFONT],"_",1))-2;
2343 if (strlen(city->tz)<w) w = strlen(city->tz);
2344 strncpy(urban_entry[1].string, city->tz, w);
2345 urban_entry[1].string[w] = '\0';
2346 urban_entry[1].caret = strlen(urban_entry[1].string);
2347 }
2348 ptr = num2str(city->lat, urban_entry[2].string, Context->flags.dms);
2349 urban_entry[2].caret = strlen(ptr);
2350 ptr = num2str(city->lon, urban_entry[3].string, Context->flags.dms);
2351 urban_entry[3].caret = strlen(ptr);
2352 sprintf(urban_entry[4].string, "%d", city->size);
2353 urban_entry[4].caret = 1;
2354 }
2355
2356 void
setupUrban(mode)2357 setupUrban(mode)
2358 int mode;
2359 {
2360 int i, vskip;
2361 char s[80];
2362
2363 if (!do_urban) return;
2364
2365 if (mode == -2) {
2366 urban_t[0] = urban_t[2] = 7;
2367 urban_t[1] = 15 + UrbanGeom.width/2;
2368 urban_t[3] = (UrbanGeom.width - 120)/2;
2369 urban_t[4] = UrbanGeom.width - 100;
2370 urban_x[0] = 100;
2371 urban_x[1] = 100 + (UrbanGeom.width+1)/2;
2372 urban_x[2] = 80;
2373 urban_x[3] = 20 + UrbanGeom.width/2;
2374 urban_x[4] = UrbanGeom.width-40;
2375 for (i=0; i<=1; i++)
2376 urban_y[i] = UrbanCaller->gdata->mapstrip/2 - 1;
2377 for (i=2; i<=4; i++)
2378 urban_y[i] = 2*UrbanCaller->gdata->mapstrip - 1;
2379 urban_w[0] = urban_w[1] = (UrbanGeom.width-210)/2;
2380 urban_w[2] = urban_w[3] = (UrbanGeom.width-320)/2;
2381 urban_w[4] = 35;
2382 return;
2383 }
2384
2385 BasicSettings(UrbanCaller);
2386 XSetWindowColormap(dpy, Urban, UrbanCaller->gdata->cmap);
2387 XSetWindowBackground(dpy, Urban, UrbanCaller->gdata->pixel[MENUBGCOLOR]);
2388
2389 urbanh = UrbanGeom.height-2*UrbanCaller->gdata->menustrip - 1;
2390 vskip = 3*UrbanCaller->gdata->menustrip/8;
2391 urban_lasthint = '\0';
2392
2393 if (mode == -1) {
2394 XClearArea(dpy, Urban, 0,0, UrbanGeom.width,
2395 UrbanGeom.height, False);
2396 for (i=0; i<=N_URBAN; i++)
2397 drawButton(Urban, i, 0);
2398
2399 BasicSettings(UrbanCaller);
2400 for (i=0; i<=4; i++) {
2401 strcpy(s, Label[L_CITYNAME+i]);
2402 XDrawImageString(dpy, Urban, UrbanCaller->gdata->wingc,
2403 urban_t[i],
2404 urban_y[i]+
2405 UrbanCaller->gdata->font[MENUFONT]->max_bounds.ascent+4,
2406 s, strlen(s));
2407 XDrawRectangle(dpy, Urban, UrbanCaller->gdata->wingc,
2408 urban_x[i], urban_y[i], urban_w[i],
2409 UrbanCaller->gdata->menustrip);
2410 }
2411 }
2412
2413 for (i=0; i<=4; i++)
2414 if (text_input != URBAN_INPUT+i)
2415 showCaret(UrbanCaller, Urban, &urban_entry[i],
2416 urban_x[i]+6, urban_y[i], 0);
2417 for (i=0; i<=4; i++)
2418 if (text_input == URBAN_INPUT+i || text_input < URBAN_INPUT) {
2419 XSetWindowBackground(dpy, Urban, UrbanCaller->gdata->pixel[OPTIONBGCOLOR]);
2420 XClearArea(dpy, Urban, urban_x[i]+1, urban_y[i]+1,
2421 urban_w[i]-1,
2422 UrbanCaller->gdata->menustrip-1, False);
2423 XSetBackground(dpy, UrbanCaller->gdata->wingc,
2424 UrbanCaller->gdata->pixel[OPTIONBGCOLOR]);
2425 XSetForeground(dpy, UrbanCaller->gdata->wingc,
2426 UrbanCaller->gdata->pixel[OPTIONFGCOLOR]);
2427 XDrawImageString(dpy, Urban, UrbanCaller->gdata->wingc,
2428 urban_x[i]+6,
2429 urban_y[i]+ UrbanCaller->gdata->font[MENUFONT]->max_bounds.ascent +4,
2430 urban_entry[i].string, strlen(urban_entry[i].string));
2431 if (text_input == URBAN_INPUT+i)
2432 showCaret(UrbanCaller, Urban, &urban_entry[i],
2433 urban_x[i]+6, urban_y[i], 1);
2434 }
2435 if (urban_newhint == '?')
2436 urban_newhint = urban_lasthint = '(';
2437 else
2438 showUrbanHint(NULL);
2439 }
2440
2441 void
PopUrban(Context)2442 PopUrban(Context)
2443 struct Sundata * Context;
2444 {
2445 int i, w, h, a, b, x=0, y=0;
2446
2447 do_urban = 1 - do_urban;
2448
2449 if (!do_urban) {
2450 XDestroyWindow(dpy, Urban);
2451 Urban = 0;
2452 UrbanCaller = NULL;
2453 return;
2454 }
2455
2456 if (!Urban)
2457 Urban = newWindow(NULL, &UrbanGeom, 6);
2458
2459 XSelectInput(dpy, Urban, 0);
2460 UrbanCaller = Context;
2461
2462 UrbanGeom.height = UrbanGeom.h_mini
2463 = (22 * Context->gdata->menustrip)/4;
2464 setupUrban(-2);
2465 for (i=0; i<=4; i++) {
2466 w = (urban_w[i]/
2467 XTextWidth(UrbanCaller->gdata->font[MENUFONT], "_", 1)) - 2;
2468 resetStringLength(w, &urban_entry[i]);
2469 }
2470
2471 if (!getPlacement(Context->win, &Context->geom.x, &Context->geom.y, &w, &h)) {
2472 x = Context->geom.x + UrbanGeom.x - horiz_drift - 5;
2473 a = Context->geom.y + h + 6;
2474 if (do_menu && Context == MenuCaller)
2475 a += MenuGeom.height + MenuGeom.y + vert_drift + 2;
2476 b = Context->geom.y - UrbanGeom.height - UrbanGeom.y - 2*vert_drift -28;
2477 if (b < TOPTITLEBARHEIGHT ) b = TOPTITLEBARHEIGHT;
2478 if (a > (int) DisplayHeight(dpy,scr)
2479 - 2*UrbanGeom.height -vert_drift -20)
2480 a = b;
2481 y = (placement<=NE)? a : b;
2482 }
2483 setSizeHints(NULL, 6);
2484 XMoveWindow(dpy, Urban, x, y);
2485 XResizeWindow(dpy, Urban, UrbanGeom.width, UrbanGeom.height);
2486 XMapRaised(dpy, Urban);
2487 XMoveWindow(dpy, Urban, x, y);
2488 XFlush(dpy);
2489 usleep(2*TIMESTEP);
2490 setupUrban(-1);
2491 setProtocols(NULL, 6);
2492 }
2493
2494 void
activateUrban()2495 activateUrban()
2496 {
2497 }
2498
2499 void
processUrbanAction(Context,x,y,button,evtype)2500 processUrbanAction(Context, x, y, button, evtype)
2501 Sundata * Context;
2502 int x, y, button, evtype;
2503 {
2504 static int move_pos;
2505 static int click_pos;
2506 int i, j, vskip, but_pos;
2507 KeySym key;
2508
2509 if (evtype == MotionNotify && move_pos>=0) {
2510 drawButton(Urban, move_pos, -2);
2511 move_pos = -1;
2512 }
2513
2514 if (evtype == ButtonRelease && click_pos>=0) {
2515 drawButton(Urban, click_pos, 0);
2516 click_pos = -1;
2517 }
2518
2519 vskip = 3*Context->gdata->menustrip/8;
2520
2521 for (i=0; i<=4; i++)
2522 if (evtype==ButtonRelease && x>=urban_x[i]+1 &&
2523 x<=urban_x[i]+urban_w[i] &&
2524 y>=urban_y[i] && y<=urban_y[i]+Context->gdata->menustrip) {
2525 text_input = URBAN_INPUT+i;
2526 but_pos =
2527 (x-urban_x[i]-6)/XTextWidth(UrbanCaller->gdata->font[MENUFONT], "_", 1);
2528 j = strlen(urban_entry[i].string);
2529 if (but_pos<0) but_pos = 0;
2530 if (but_pos>j) but_pos = j;
2531 urban_entry[i].caret = but_pos;
2532 setupUrban(0);
2533 return;
2534 }
2535
2536 if (evtype==ButtonRelease) {
2537 text_input = NULL_INPUT;
2538 setupUrban(0);
2539 }
2540
2541 if (y>urbanh && y<urbanh+Context->gdata->menustrip) {
2542 but_pos = getButton(Urban, x, y);
2543 if (but_pos>=N_URBAN)
2544 urban_newhint = '\033';
2545 else
2546 if (but_pos>=0)
2547 urban_newhint = UrbanKey[2*but_pos];
2548 if (evtype==MotionNotify) {
2549 if (but_pos>=0 && but_pos<=N_URBAN) {
2550 showUrbanHint(NULL);
2551 drawButton(Urban, but_pos, -1);
2552 move_pos = but_pos;
2553 }
2554 }
2555 if (evtype==ButtonPress && but_pos>=0) {
2556 drawButton(Urban, but_pos, 1);
2557 click_pos = but_pos;
2558 }
2559 if (evtype==ButtonRelease) {
2560 if (but_pos<0) return;
2561 if (but_pos<N_URBAN) {
2562 if (button<=2)
2563 key = (KeySym)tolower(urban_newhint);
2564 else
2565 key = (KeySym)urban_newhint;
2566 showUrbanHint(NULL);
2567 processKey(Urban, key);
2568 } else
2569 PopUrban(Context);
2570 }
2571 }
2572 if (evtype==MotionNotify &&
2573 (y<=urbanh || y>=urbanh+Context->gdata->menustrip)) {
2574 urban_newhint = 'U';
2575 showUrbanHint(NULL);
2576 }
2577 }
2578
2579 struct Sundata *
parentContext(Context)2580 parentContext(Context)
2581 struct Sundata * Context;
2582 {
2583 struct Sundata * ParentContext;
2584
2585 ParentContext = Seed;
2586 while (ParentContext && ParentContext->next != Context)
2587 ParentContext = ParentContext->next;
2588 return ParentContext;
2589 }
2590
2591 void
setAuxilWins(Context,mode)2592 setAuxilWins(Context, mode)
2593 Sundata * Context;
2594 int mode;
2595 {
2596 #define NUMWIDGETS 5
2597
2598
2599 int * bool_state[NUMWIDGETS] = {
2600 &do_menu, &do_filesel, &do_zoom, &do_option, &do_urban };
2601
2602 Window * window[NUMWIDGETS] = { &Menu, &Filesel, &Zoom, &Option, &Urban };
2603
2604 struct Sundata ** caller[NUMWIDGETS] = {
2605 &MenuCaller, &FileselCaller, &ZoomCaller, &OptionCaller, &UrbanCaller };
2606
2607 char * char_newhint[NUMWIDGETS] = {
2608 (char *)&menu_newhint, NULL,
2609 &zoom_newhint, &option_newhint, &urban_newhint };
2610
2611 setupCB setup_proc[NUMWIDGETS] = {
2612 &setupMenu, &setupFilesel, &setupZoom, &setupOption, &setupUrban };
2613
2614 popCB pop_proc[NUMWIDGETS] = {
2615 &PopMenu, &PopFilesel, &PopZoom, &PopOption, &PopUrban };
2616
2617 int i, announce=1;
2618
2619 if (option_changes && mode==RESET) mode = REMAP;
2620
2621 for (i=0; i<NUMWIDGETS; i++) if (*bool_state[i]) {
2622 if (announce && verbose && mode!=RESET) {
2623 fprintf(stderr,
2624 "Resetting auxiliary widgets in mode %d...\n", mode);
2625 announce = 0;
2626 }
2627
2628 switch(mode) {
2629
2630 case RESET:
2631 if (Context == *caller[i]) {
2632 *bool_state[i] = 1;
2633 *caller[i] = Context;
2634 setup_proc[i](-1);
2635 }
2636 break;
2637
2638 case REMAP:
2639 if (Context != *caller[i]) break;
2640 case REATTRIB:
2641 *bool_state[i] = 0;
2642 if (*window[i])
2643 XUnmapWindow(dpy, *window[i]);
2644 if (char_newhint[i])
2645 *char_newhint[i] = ' ';
2646 pop_proc[i](Context);
2647 break;
2648
2649 case DESTROY:
2650 if (Context == *caller[i]) {
2651 if (*window[i]) {
2652 XDestroyWindow(dpy, *window[i]);
2653 *window[i] = 0;
2654 }
2655 *bool_state[i] = 0;
2656 *caller[i] = NULL;
2657 }
2658 break;
2659
2660 case ICONIFY:
2661 if (Context == *caller[i])
2662 XIconifyWindow(dpy, *window[i], scr);
2663 break;
2664
2665 case DEICONIFY:
2666 if (Context == *caller[i]) {
2667 XMapWindow(dpy, *window[i]);
2668 setup_proc[i](-1);
2669 }
2670 break;
2671
2672 }
2673 }
2674
2675 XFlush(dpy);
2676 if (mode == REMAP) usleep(2*TIMESTEP);
2677 }
2678
RaiseAndFocus(win)2679 void RaiseAndFocus(win)
2680 Window win;
2681 {
2682 XFlush(dpy);
2683 XRaiseWindow(dpy, win);
2684 XSetInputFocus(dpy, win, RevertToPointerRoot, CurrentTime);
2685 }
2686
2687 /*
2688 * Free GC's.
2689 */
2690
2691 void
destroyGCs(Context)2692 destroyGCs(Context)
2693 Sundata * Context;
2694 {
2695 int i;
2696 if (Context->gdata->links>0) {
2697 --Context->gdata->links;
2698 return;
2699 }
2700
2701 XFreeGC(dpy, Context->gdata->wingc);
2702 Context->gdata->wingc = 0;
2703 XFreeGC(dpy, Context->gdata->pixgc);
2704 Context->gdata->pixgc = 0;
2705
2706 if (runlevel!=IMAGERECYCLE && Context->gdata->cmap!=cmap0)
2707 XFreeColormap(dpy, Context->gdata->cmap);
2708
2709 for (i=0; i<NUMFONTS; i++)
2710 XFreeFont(dpy, Context->gdata->font[i]);
2711
2712 free(Context->gdata);
2713 }
2714
2715 /*
2716 * Free resources.
2717 */
2718
2719 void
shutDown(Context,all)2720 shutDown(Context, all)
2721 struct Sundata * Context;
2722 int all;
2723 {
2724 struct Sundata * ParentContext, *NextContext;
2725
2726 if (all<0)
2727 Context = Seed;
2728
2729 repeat:
2730 fflush(stderr);
2731
2732 NextContext = Context->next;
2733 ParentContext = parentContext(Context);
2734
2735 if (runlevel!=IMAGERECYCLE) {
2736 if (Context->xim) {
2737 XDestroyImage(Context->xim);
2738 Context->xim = NULL;
2739 }
2740 if (Context->ximdata) {
2741 free(Context->ximdata);
2742 Context->ximdata = NULL;
2743 }
2744 while (Context->label) {
2745 struct TextLabel *ptr;
2746 ptr = (Context->label)->next;
2747 free(Context->label->text);
2748 free(Context->label);
2749 Context->label = ptr;
2750 }
2751 if (Context->mappix) {
2752 XFreePixmap(dpy, Context->mappix);
2753 Context->mappix = 0;
2754 }
2755 if (Context->daypixel) {
2756 free(Context->daypixel);
2757 Context->daypixel = NULL;
2758 }
2759 if (Context->nightpixel) {
2760 free(Context->nightpixel);
2761 Context->nightpixel = NULL;
2762 }
2763 if (Context->vmfpixels) {
2764 free(Context->vmfpixels);
2765 Context->vmfpixels = NULL;
2766 }
2767 if (Context->tr1) {
2768 free(Context->tr1);
2769 Context->tr1 = NULL;
2770 }
2771 if (Context->tr2) {
2772 free(Context->tr2);
2773 Context->tr2 = NULL;
2774 }
2775 if (Context->daywave) {
2776 free(Context->daywave);
2777 Context->daywave = NULL;
2778 }
2779 }
2780 destroyGCs(Context);
2781
2782 Context->flags.hours_shown = 0;
2783
2784 if (all) {
2785 last_time = 0;
2786
2787 if (Context->win) {
2788 setAuxilWins(Context, DESTROY);
2789 if (Context == RootCaller) {
2790 RootCaller = NULL;
2791 do_root = 0;
2792 }
2793 XDestroyWindow(dpy, Context->win);
2794 Context->win = 0;
2795 }
2796 if (Context->clock_img_file) {
2797 free(Context->clock_img_file);
2798 Context->clock_img_file = NULL;
2799 }
2800 if (Context->map_img_file) {
2801 free(Context->map_img_file);
2802 Context->map_img_file = NULL;
2803 }
2804
2805 free(Context->spotsizes);
2806 free(Context->sizelimits);
2807
2808 if (all<0) {
2809 free(Context);
2810 if (NextContext) {
2811 Context = NextContext;
2812 goto repeat;
2813 }
2814 else {
2815 endup:
2816 if (zoompix) XFreePixmap(dpy, zoompix);
2817 if (textpix) XFreePixmap(dpy, textpix);
2818 if (rootpix) XFreePixmap(dpy, rootpix);
2819 XCloseDisplay(dpy);
2820 if (dirtable) free(dirtable);
2821 exit(0);
2822 }
2823 }
2824 if (ParentContext)
2825 ParentContext->next = Context->next;
2826 else
2827 Seed = Context->next;
2828 free(Context);
2829 if (Seed == NULL) goto endup;
2830 }
2831 }
2832