1 /* $Header: /home/yav/catty/fkiss/RCS/fkiss.c,v 1.68 2000/10/17 05:00:28 yav Exp $
2  * fkiss "French-KISS!" (Not Fast-KISS, sorry...)
3  *  - KISekae Set system for X Window System
4  * written by yav <yav@bigfoot.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 char id_fkiss[] = "$Id: fkiss.c,v 1.68 2000/10/17 05:00:28 yav Exp $";
22 
23 #include <X11/Xos.h>
24 #include <X11/Xlib.h>
25 #include <X11/Xutil.h>
26 #include <X11/keysym.h>
27 #include <stdio.h>
28 
29 #include "config.h"
30 
31 #include "headers.h"
32 #include "fkiss.h"
33 #include "work.h"
34 #include "timer.h"
35 #define PUBLIC_FKISS_C
36 #include "extern.h"
37 
38 
39 #include "icon.xbm"
40 
41 static int topbw = 1;		/* top window border width */
42 static int viewx = 0;
43 static int viewy;
44 static int viewbw = 0;		/* view window border width */
45 static Window imgwin = None;
46 static GC imggc;
47 static Pixmap world_pixmap;
48 static char *str_display = "";
49 static char *str_color[SPX_MAX];
50 static Bool pointer_move = False;
51 static int catched_dx, catched_dy, catched_cell;
52 static int catched_cell2;
53 static int catched_objx, catched_objy;
54 static int mobjn, mobjx, mobjy;
55 static int menu_mode = 0;	/* bit0: off:top on:bottom  */
56 static int catch_x, catch_y;
57 static int mapping_changed_cell = -1;
58 static int scroll_limit = 1;
59 static int pesi_count;
60 static int fixed = -1;
61 static int unfixed = 100;
62 static int alpha_level = 0;
63 static int info_mode = 0;	/* != 0 : information window on */
64 static char *tmpdir = "/tmp";	/* temporary directory to extract files */
65 static GC *paint_gc = NULL;	/* [colcnt] */
66 static GC true_color_gc;
67 static char **extract_files = NULL;
68 static char **conf_files = NULL;
69 static char *startup_sound_file = NULL;
70 static int image_mode = -1;
71 static int true_color_cell;
72 typedef struct {
73   char *suffix;
74   char *command;
75 } ARTBL;
76 static ARTBL artype[] = {
77   {".lzh",	"lha xfqw=%D %A"},
78   {".tar.gz",	"tar xzCf %D %A"},
79   {".tgz",	"tar xzCf %D %A"},
80   {".hes",	"hesper '-k%K' %A|lha xfiqw=%D -"},
81   {NULL, NULL}
82 };
83 
84 /*
85  * Document file browse command
86  * Uncomment only one line in following #define DOC_COMMAND lines.
87  */
88 #define DOC_COMMAND	"xemacs"
89 /* #define DOC_COMMAND	"xemacs --eval '(view-file \"%P\")'" */
90 /* #define DOC_COMMAND	"emacs" */
91 /* #define DOC_COMMAND	"kedit" */
92 /* #define DOC_COMMAND	"xterm -e less" */
93 /* #define DOC_COMMAND	"kterm -e less" */
94 /* #define DOC_COMMAND	"(cd %A; kterm -km sjis -e jless %F) &" */
95 
96 static char doc_suffix_free[] = "(free)";
97 static char *doc_suffix[] = {
98   ".doc", ".DOC", ".txt", ".TXT",
99   doc_suffix_free, doc_suffix_free, doc_suffix_free, doc_suffix_free,
100   doc_suffix_free, doc_suffix_free, doc_suffix_free, doc_suffix_free,
101   doc_suffix_free, doc_suffix_free, doc_suffix_free, doc_suffix_free,
102   NULL				/* End mark */
103 };
104 char *doc_command = DOC_COMMAND;
105 
106 #define BUTTON_FUNC_NONE	0
107 #define BUTTON_FUNC_CELL	1
108 #define BUTTON_FUNC_ICONIFY	2
109 #define BUTTON_FUNC_COMMENT	3
110 #define BUTTON_FUNC_MAX	4
111 
112 static int button_func_tbl[BUTTON_FUNC_MAX] = {
113   BUTTON_FUNC_NONE,		/* 0 AnyButton */
114   BUTTON_FUNC_CELL,		/* 1 Button1 */
115   BUTTON_FUNC_ICONIFY,		/* 2 Button2 */
116   BUTTON_FUNC_COMMENT		/* 3 Button3 */
117 };
118 
print_version()119 void print_version()
120 {
121   printf("%s %s\n", str_fullname, str_version);
122 }
123 
opt_version()124 void opt_version()
125 {
126   print_version();
127   kiss_exit(0);
128 }
129 
print_compile_options()130 void print_compile_options()
131 {
132   int i, n;
133 
134   n = 0;
135   while (coptions[n] != NULL) {
136     for (i = 0; i < 4; i++) {
137       if (coptions[n] == NULL)
138 	break;
139       fprintf(stderr, "%s%s", i?"\t":"", coptions[n]);
140       n++;
141     }
142     fputc('\n', stderr);
143   }
144 }
145 
usage()146 void usage()
147 {
148   printf("usage : %s [option ...] [file.lzh ...] [file.cnf]\n",
149 	  *oargv);
150   printf("option :\n");
151   printf("  -display dpy\n");
152   printf("  -geometry WxH+X+Y\n");
153   printf("  -verbose\n");
154   printf("  -font name\n");
155   printf("  -fg color\n");
156   printf("  -bg color\n");
157   printf("  -cursor [0-3]\n");
158   printf("Report bugs to yav@bigfoot.com\n");
159   kiss_exit(0);
160 }
161 
exec_test()162 void exec_test()
163 {
164   char *p;
165   char **av;
166   int i;
167 
168   av = (char **)ks_malloc(sizeof(char *)*(oargc+2));
169   *av = "time";
170   for (i = 0; i < oargc; i++) {
171     p = *(oargv+i);
172     if (strcmp(p, "-t") == 0)
173       p = "-test";
174     *(av+1+i) = p;
175   }
176   *(av+1+i) = NULL;
177   execvp(*av, av);
178   /* time command exec error! */
179   msg("E ``%s'' exec error!\n", *av);
180 }
181 
is_free_doc_suffix(p)182 int is_free_doc_suffix(p)
183      char *p;
184 {
185   return (p == doc_suffix_free);
186 }
187 
188 /* new, 1998-12-27, dirk */
set_maxtimer(str)189 void set_maxtimer(str)
190      char *str;
191 {
192 /* maybe someone wants to disable all timers ? */
193 #define MIN_MAXTIMER	0
194 #define MAX_MAXTIMER	(MAXSHORT/2)
195 
196   int result, maxtimer;
197 
198   result = sscanf(str, " %d ", &maxtimer);
199   if (result == EOF || result == 0) {
200     fprintf(stderr,"\"%s\" is not a valid maxtimer value, ignored !\n", str);
201     return;
202   }
203   debug_printf("\tstr=\"%s\", result=%d, maxtimer=%d\n",
204 	       str, result, maxtimer);
205 
206   if (maxtimer < MIN_MAXTIMER || maxtimer > MAX_MAXTIMER) {
207     fprintf(stderr,
208 	    "invalid maxtimer value %d ignored, must be between %d and %d !\n",
209 	    maxtimer, MIN_MAXTIMER, MAX_MAXTIMER);
210     return;
211   }
212 
213   MAXTIMER   = maxtimer; /* ignore higher timer channels */
214   WARN_TIMER = maxtimer; /* warn if higher timer channel, never happens */
215 
216 }
217 
218 /* new, 1998-12-27, dirk */
set_maxevent(str)219 void set_maxevent(str)
220      char *str;
221 {
222 /* maybe someone wants to disable all events ? */
223 #define MIN_MAXEVENT	0
224 #define MAX_MAXEVENT	(MAXSHORT/2)
225 
226   int result, maxevent;
227 
228   result = sscanf(str, " %d ", &maxevent);
229   if (result == EOF || result == 0) {
230     fprintf(stderr,"\"%s\" is not a valid maxevent value, ignored !\n", str);
231     return;
232   }
233   debug_printf("\tstr=\"%s\", result=%d, maxevent=%d\n",
234 	       str, result, maxevent);
235 
236   if (maxevent < MIN_MAXEVENT || maxevent > MAX_MAXEVENT) {
237     fprintf(stderr,
238 	    "invalid maxevent value %d ignored, must be between %d and %d !\n",
239 	    maxevent, MIN_MAXEVENT, MAX_MAXEVENT);
240     return;
241   }
242 
243   MAXEVENT   = maxevent; /* ignore higher event numbers */
244   WARN_EVENT = maxevent; /* warn if higher event number, never happens */
245 
246 }
247 
248 /* new, 1998-12-27, dirk */
set_maxsoundfile(str)249 void set_maxsoundfile(str)
250      char *str;
251 {
252 /* maybe someone wants to disable all soundfiles ? */
253 #define MIN_MAXSOUNDFILE	0
254 #define MAX_MAXSOUNDFILE	(MAXSHORT/2)
255 
256   int result, maxsoundfile;
257 
258   result = sscanf(str, " %d ", &maxsoundfile);
259   if (result == EOF || result == 0) {
260     fprintf(stderr,"\"%s\" is not a valid maxsoundfile value, ignored !\n", str);
261     return;
262   }
263   debug_printf("\tstr=\"%s\", result=%d, maxsoundfile=%d\n",
264 	       str, result, maxsoundfile);
265 
266   if (maxsoundfile < MIN_MAXSOUNDFILE || maxsoundfile > MAX_MAXSOUNDFILE) {
267     fprintf(stderr,
268 	    "invalid maxsoundfile value %d ignored, must be between %d and %d !\n",
269 	    maxsoundfile, MIN_MAXSOUNDFILE, MAX_MAXSOUNDFILE);
270     return;
271   }
272 
273   MAXSOUNDFILE   = maxsoundfile; /* ignore higher soundfile numbers */
274   WARN_SOUNDFILE = maxsoundfile; /* warn if higher soundfile number, never happens */
275 
276 }
277 
278 /* 1999-03-14, dirk --
279 ** silly dirk made a mistake the first time. It was easier than I thought.
280 */
set_maxaction(str)281 void set_maxaction(str)
282      char *str;
283 {
284 /* maybe someone wants to disable all actions for some strange testing ? */
285 #define MIN_MAXACTION	0
286 #define MAX_MAXACTION	(MAXSHORT/2)
287   int result, maxaction = 0;
288 
289   result = sscanf(str, " %d ", &maxaction);
290   if (result == EOF || result == 0) {
291     fprintf(stderr,"\"%s\" is not a valid maxaction value, ignored !\n",str);
292     return;
293   }
294   debug_printf("\tstr=\"%s\", result=%d, maxaction=%d\n",
295 	       str, result, maxaction);
296 
297   if (maxaction < MIN_MAXACTION || maxaction > MAX_MAXACTION) {
298     fprintf(stderr,
299 	    "invalid maxaction value %d ignored, must be between %d and %d !\n",
300 	    maxaction, MIN_MAXACTION, MAX_MAXACTION);
301     return;
302   }
303   MAXACTION   = maxaction; /* ignore higher action numbers */
304   WARN_ACTION = maxaction; /* warn if higher action number */
305 }
306 
opt_add_doc_suffix(str)307 void opt_add_doc_suffix(str)
308      char *str;
309 {
310   char **p;
311 
312   for (p = doc_suffix; *p; p++) {
313     if (is_free_doc_suffix(*p)) {
314       *p = str;
315       return;
316     }
317   }
318 }
319 
opt_del_doc_suffix(str)320 void opt_del_doc_suffix(str)
321      char *str;
322 {
323   char **p;
324 
325   for (p = doc_suffix; *p; p++) {
326     if (!is_free_doc_suffix(*p) && !strcmp(*p, str)) {
327       *p = doc_suffix_free;
328       return;
329     }
330   }
331 }
332 
search_dir_list(name,list0)333 char *search_dir_list(name, list0)
334      char *name;
335      char **list0;
336 {
337   char *p;
338   char **list;
339 
340   if (list0 != NULL) {
341     for (list = list0; *list != NULL; list++) {
342       if (strcmp(*list, name) == 0)
343 	return *list;
344     }
345     for (list = list0; *list != NULL; list++) {
346       p = dos_pathname(*list);
347       if (strcmp(p, name) == 0) {
348 	free(p);
349 	return *list;
350       }
351       free(p);
352     }
353     for (list = list0; *list != NULL; list++) {
354       p = dos_filename(*list);
355       if (strcmp(p, name) == 0) {
356 	free(p);
357 	return *list;
358       }
359       free(p);
360     }
361   }
362   return NULL;
363 }
364 
ks_filename0(name)365 char *ks_filename0(name)
366      char *name;
367 {
368   char *r;
369   char *p;
370   char *dir;
371   char *buf;
372 
373   r = NULL;
374   buf = get_filename(name);
375   dir = ks_strdup(name);
376   p = rindex(dir, '/');
377   if (p == NULL) {
378     free(dir);
379     dir = NULL;
380   } else {
381     *(p+1) = '\0';
382     dir = ks_realloc(dir, strlen(dir) + strlen(buf) + 1);
383     strcat(dir, buf);
384     if ((p = search_dir_list(dir, conf_files)) != NULL) {
385       r = ks_malloc(strlen(conf_dir) + 1 + strlen(p) + 1);
386       sprintf(r, "%s/%s", conf_dir, p);
387       free(dir);
388       return r;
389     } else if ((p = search_dir_list(dir, extract_files)) != NULL) {
390       r = ks_malloc(strlen(extract_dir) + 1 + strlen(p) + 1);
391       sprintf(r, "%s/%s", extract_dir, p);
392       free(dir);
393       return r;
394     }
395   }
396   if ((p = search_dir_list(buf, conf_files)) != NULL) {
397     r = ks_malloc(strlen(conf_dir) + 1 + strlen(p) + 1);
398     sprintf(r, "%s/%s", conf_dir, p);
399   } else if ((p = search_dir_list(buf, extract_files)) != NULL) {
400     r = ks_malloc(strlen(extract_dir) + 1 + strlen(p) + 1);
401     sprintf(r, "%s/%s", extract_dir, p);
402   }
403   return r;
404 }
405 
ks_filename(name)406 char *ks_filename(name)
407      char *name;
408 {
409   char *r;
410   char *buf;
411 
412   r = ks_filename0(name);
413   if (r == NULL) {
414     buf = dos_pathname(name);
415     r = ks_filename0(buf);
416     free(buf);
417   }
418   return r;
419 }
420 
ks_fopen(name,mode)421 FILE *ks_fopen(name, mode)
422      char *name;
423      char *mode;
424 {
425   FILE *fp;
426   char *buf;
427 
428   buf = ks_filename(name);
429   debug_printf("ks_fopen [%s] -> [%s]\n", name, buf);
430   fp = fopen(buf, mode);
431   free(buf);
432   return fp;
433 }
434 
read_directory()435 void read_directory()
436 {
437   if (extract_dir != NULL && strcmp(extract_dir, conf_dir)) {
438     debug_printf("read_directory extract_dir ``%s''\n", extract_dir);
439     extract_files = dir_ls(extract_dir, NULL);
440   }
441   debug_printf("read_directory conf_dir ``%s''\n", conf_dir);
442   conf_files = dir_ls(conf_dir, NULL);
443 }
444 
free_directory()445 void free_directory()
446 {
447   dir_free(extract_files);
448   dir_free(conf_files);
449 }
450 
get_effective_area(buf,w,h,newx,newy,neww,newh,byteperpixel)451 void get_effective_area(buf, w, h, newx, newy, neww, newh, byteperpixel)
452      unsigned char *buf;
453      int w;
454      int h;
455      int *newx;
456      int *newy;
457      int *neww;
458      int *newh;
459      int byteperpixel;
460 {
461   int x, y;
462   int xtop, xend, ytop, yend;
463   Bool f;
464   unsigned char *p;
465 
466   xtop = w;
467   ytop = h;
468   xend = yend = 0;
469   for (y = 0; y < h; y++) {
470     f = False;
471     p = buf;
472     for (x = 0; x < w; x++) {
473       if (*p) {
474 	f = True;
475 	if (x < xtop)
476 	  xtop = x;
477 	break;
478       }
479       p += byteperpixel;
480     }
481     p = buf + w * byteperpixel;
482     for (x = w-1; x >= 0; --x) {
483       p -= byteperpixel;
484       if (*p) {
485 	f = True;
486 	if (x > xend)
487 	  xend = x;
488 	break;
489       }
490     }
491     buf += w * byteperpixel;
492     if (f) {
493       if (y < ytop)
494 	ytop = y;
495       if (y > yend)
496 	yend = y;
497     }
498   }
499   *newx = xtop;
500   *newy = ytop;
501   *neww = xend - xtop + 1;
502   if (*neww < 0)
503     *neww = 0;
504   *newh = yend - ytop + 1;
505   if (*newh < 0)
506     *newh = 0;
507 }
508 
store_image(iline,buf,w,h,newx,newy,neww,newh)509 unsigned char *store_image(iline, buf, w, h, newx, newy, neww, newh)
510      long **iline;
511      unsigned char *buf;
512      int w;
513      int h;
514      int newx;
515      int newy;
516      int neww;
517      int newh;
518 {
519   int x, y, len;
520   unsigned char lastpix;
521   unsigned char *p;
522   unsigned char *np;
523   unsigned char *nbuf;
524   long *lp;
525 
526   lp = (long *)ks_malloc(sizeof(*lp) * newh);
527   *iline = lp;
528   np = nbuf = (unsigned char *)ks_malloc(neww * 2 * newh);
529   for (y = newy; y < newy+newh; y++) {
530     *lp++ = np - nbuf;
531     p = buf + w*y + newx;
532     lastpix = *p;
533     len = 0;
534     for (x = 0; x < neww; p++, x++) {
535       if (*p == lastpix && ++len < 255)
536 	continue;
537       *np++ = lastpix;
538       *np++ = len;
539       len = *p != lastpix;
540       lastpix = *p;
541     }
542     if (len) {
543       *np++ = lastpix;
544       *np++ = len;
545     }
546   }
547   return (unsigned char *)ks_realloc(nbuf, np - nbuf);
548 }
549 
get_colorpixel(p)550 unsigned long get_colorpixel(p)
551      unsigned char *p;
552 {
553   int b, r, g, a;
554 
555   b = *p++;
556   g = *p++;
557   r = *p++;
558   a = *p++;
559   return (a<<24)|(r<<16)|(g<<8)|b;
560 }
561 
set_colorpixel(p,pixel)562 void set_colorpixel(p, pixel)
563      unsigned char **p;
564      unsigned long pixel;
565 {
566   int b, r, g, a;
567 
568   b = pixel & 0xff;
569   pixel >>= 8;
570   g = pixel & 0xff;
571   pixel >>= 8;
572   r = pixel & 0xff;
573   pixel >>= 8;
574   a = pixel;
575 
576   *((*p)++) = b;
577   *((*p)++) = g;
578   *((*p)++) = r;
579   *((*p)++) = a;
580 }
581 
store_image32(iline,buf,w,h,newx,newy,neww,newh)582 unsigned char *store_image32(iline, buf, w, h, newx, newy, neww, newh)
583      long **iline;
584      unsigned char *buf;
585      int w;
586      int h;
587      int newx;
588      int newy;
589      int neww;
590      int newh;
591 {
592   int x, y, len;
593   unsigned long lastpix;
594   unsigned char *p;
595   unsigned char *np;
596   unsigned char *nbuf;
597   long *lp;
598 
599   lp = (long *)ks_malloc(sizeof(*lp) * newh);
600   *iline = lp;
601   np = nbuf = (unsigned char *)ks_malloc(neww * newh * (sizeof(unsigned long) + 1));
602   for (y = newy; y < newy+newh; y++) {
603     *lp++ = np - nbuf;
604     p = buf + (w*y + newx) * 32/8;
605     lastpix = get_colorpixel(p);
606     len = 0;
607     for (x = 0; x < neww; p += 32/8, x++) {
608       if (get_colorpixel(p) == lastpix && ++len < 255)
609 	continue;
610       set_colorpixel(&np, lastpix);
611       *np++ = len;
612       len = get_colorpixel(p) != lastpix;
613       lastpix = get_colorpixel(p);
614     }
615     if (len) {
616       set_colorpixel(&np, lastpix);
617       *np++ = len;
618     }
619   }
620   return (unsigned char *)ks_realloc(nbuf, np - nbuf);
621 }
622 
read_cell_file(fp,p)623 int read_cell_file(fp, p)
624      FILE *fp;
625      CELL *p;
626 {
627   int i, y;
628   int ox, oy, w, h;
629   int newx, newy, neww, newh;
630   int bpp;			/* bit per pixel (cel file) */
631   int byteperpixel;		/* byte per pixel (internal) */
632   unsigned char *ip, *ip2;
633   unsigned char *ip0;
634   unsigned char buf[1024];
635 
636   p->width = p->height = 0;
637   i = 4;			/* max(4, strlen(kiss_magic_number)) */
638   if (!fread(buf, i, 1, fp))
639     return 1;
640   buf[i] = '\0';
641   if (strcmp(buf, kiss_magic_number) == 0) {
642     if (!fread(buf+i, CEL_HEADER_SIZE-i, 1, fp)) {
643       msg("W ``%s'' cannot read header.\n", p->filename);
644       return 1;
645     }
646     if (buf[CEL_MARK] != 0x20 && buf[CEL_MARK] != 0x21) {
647       msg("W ``%s'' header mark 0x%02x is not cel mark (0x20 or 0x21).\n",
648 	  p->filename, buf[CEL_MARK]);
649     }
650     bpp = buf[CEL_BPP];
651     byteperpixel = (bpp + 7) / 8;
652     if (!byteperpixel)
653       byteperpixel = 1;
654     w = GET_SHORT(buf+CEL_WIDTH);
655     h = GET_SHORT(buf+CEL_HEIGHT);
656     ox = GET_SHORT(buf+CEL_XOFS);
657     oy = GET_SHORT(buf+CEL_YOFS);
658   } else {
659     bpp = 4;
660     byteperpixel = 1;
661     w = GET_SHORT(buf+CEL_OLD_WIDTH);
662     h = GET_SHORT(buf+CEL_OLD_HEIGHT);
663     ox = oy = 0;
664   }
665   debug_printf("%-16s %d %2d %3dx%3d%+4d%+4d ",
666 	       p->filename, bpp, p->colfile, w, h, ox, oy);
667   p->orgw = w;
668   p->orgh = h;
669   p->orgx = ox;
670   p->orgy = oy;
671 
672   /* check cell over screen size */
673   if ((ox+w) > imgw0 || (oy+h) > imgh0) {
674     msg("W ``%s'' %3dx%3d%+4d%+4d over screen %3dx%3d.\n",
675 	p->filename, w, h, ox, oy, imgw0, imgh0);
676     if ((ox+w) > imgw0)
677       imgw0 = ox + w;
678     if ((oy+h) > imgh0)
679       imgh0 = oy + h;
680     msg("W change screen size %3dx%3d.\n", imgw0, imgh0);
681   }
682   if ((object+p->obj)->width < ox + w)
683     (object+p->obj)->width = ox + w;
684   if ((object+p->obj)->height < oy + h)
685     (object+p->obj)->height = oy + h;
686   (object+p->obj)->ncel++;
687   i = w * h * byteperpixel;
688   ip = ip0 = (unsigned char *)ks_malloc(i);
689   if (bpp <= 4) {
690     for (y = 0; y < h && fread(ip, (w+1)/2, 1, fp); y++) {
691       /* expand pixel 4 bit -> 8 bit */
692       i = w / 2;
693       ip2 = ip + w;
694       if (w & 1)
695 	*--ip2 = *(ip+i) >> 4;
696       while (--i >= 0) {
697 	*--ip2 = *(ip+i) & 15;
698 	*--ip2 = *(ip+i) >> 4;
699       }
700       ip += w;
701     }
702   } else {
703     for (y = 0; y < h && fread(ip, w * byteperpixel, 1, fp); y++)
704       ip += w * byteperpixel;
705   }
706   if (y < h) {
707     msg("W ``%s'' read %d lines less than %d.\n", p->filename, y, h);
708     if (w)
709       bzero((char *)ip, w*(h-y)); /* clear read error line image */
710   }
711   get_effective_area(bpp > 8 ? ip0 + 3 : ip0, w, h, &newx, &newy, &neww, &newh,
712 		     byteperpixel);
713   if (neww == 0 || newh == 0) {
714     ip = NULL;
715   } else {
716     if (bpp > 8) {
717       ip = store_image32(&p->iline, ip0, w, h, newx, newy, neww, newh);
718     } else {
719       ip = store_image(&p->iline, ip0, w, h, newx, newy, neww, newh);
720     }
721   }
722   if (neww != w || newh != h) {
723     w = neww;
724     h = newh;
725     ox += newx;
726     oy += newy;
727     debug_printf("-> %3dx%3d%+4d%+4d", w, h, ox, oy);
728   }
729   free(ip0);
730   p->image = ip;
731   if (w && p) {
732     p->width = w;
733     p->height = h;
734   }
735   p->ofsx = ox;
736   p->ofsy = oy;
737   p->bpp = bpp;
738   debug_printf("\n");
739   return 0;
740 }
741 
read_cells()742 int read_cells()
743 {
744   int i;
745   CELL *cp;
746   FILE *fp;
747   char *p;
748 
749   true_color_cell = 0;
750   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
751     p = NULL;
752     if ((fp = ks_fopen(cp->filename, "rb")) != NULL) {
753       if (read_cell_file(fp, cp))
754 	p = "W ``%s'' read error! ignore.\n";
755       if (cp->bpp > 8) {
756 	image_mode = 0;
757 	true_color_cell = 1;
758       }
759       fclose(fp);
760     } else {
761       p = "W ``%s'' not found! ignore.\n";
762     }
763     if (p != NULL)
764       msg(p, cp->filename);
765   }
766   objcnt2 = 0;
767   for (i = 0; i < objcnt; i++)
768     if ((object+i)->ncel)
769       objcnt2++;
770   return 0;
771 }
772 
create_cell_pixmap()773 int create_cell_pixmap()
774 {
775   int i;
776   CELL *cp;
777 
778   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
779     if (cp->width) {
780       cp->pixmap = XCreatePixmap(dsp, imgwin, cp->width, cp->height,
781 				 screen_depth);
782       cp->gc = XCreateGC(dsp, imgwin, 0, 0);
783       /* cp->clip = XCreatePixmap(dsp, imgwin, cp->width, cp->height, 1); */
784       cp->pixpal = -1;
785     }
786   }
787   return 0;
788 }
789 
790 static GC bitmapgc0;		/* for bitmap bit reset */
791 static GC bitmapgc1;		/* for bitmap bit set */
792 #define DITHERW 8		/* dither pattern width */
793 #define DITHERH 8		/* dither pattern height */
794 #define DITHERLEVEL (DITHERW*DITHERH + 1) /* dether level */
795 static GC dithergc[DITHERLEVEL];
796 static char dither_table[DITHERH][DITHERW] = {
797   { 0, 48, 12, 60,  3, 51, 15, 63},
798   {32, 16, 44, 28, 35, 19, 47, 31},
799   { 8, 56,  4, 52, 11, 59,  7, 55},
800   {40, 24, 36, 20, 43, 27, 39, 23},
801   { 2, 50, 14, 62,  1, 49, 13, 61},
802   {34, 18, 46, 30, 33, 17, 45, 29},
803   {10, 58,  6, 54,  9, 57,  5, 53},
804   {42, 26, 38, 22, 41, 25, 37, 21}
805 };
806 
807 /* make dither pattern CG
808  * Caution! call after bitmapgc* initialized.
809  */
make_transparency_dither()810 int make_transparency_dither()
811 {
812   int x, y, n;
813   Pixmap px;
814 
815   for (n = 0; n < DITHERLEVEL; n++) {
816     px = XCreatePixmap(dsp, imgwin, DITHERW, DITHERH, 1);
817     XFillRectangle(dsp, px, bitmapgc0, 0, 0, DITHERW, DITHERH);
818     for (y = 0; y < DITHERH; y++) {
819       for (x = 0; x < DITHERW; x++) {
820 	if (n > dither_table[y][x])
821 	  XDrawPoint(dsp, px, bitmapgc1, x, y);
822       }
823     }
824     dithergc[n] = XCreateGC(dsp, px, 0, 0);
825     XSetForeground(dsp, dithergc[n], 0);
826     XSetStipple(dsp, dithergc[n], px);
827     XSetFillStyle(dsp, dithergc[n], FillStippled);
828   }
829   return DITHERLEVEL;
830 }
831 
832 /* set cell transparency level */
set_transparency(cp,n)833 void set_transparency(cp, n)
834      CELL *cp;
835      int n;			/* transparency [0, 256] */
836 {
837   if (!transparency_mode)
838     return;
839 
840   if (cp->transclip == None)
841     cp->transclip = XCreatePixmap(dsp, imgwin, cp->width, cp->height, 1);
842   XCopyArea(dsp, cp->clip, cp->transclip, bitmapgc1,
843 	    0, 0, cp->width, cp->height, 0, 0);
844   cp->transparency = n;
845   n = (n * (DITHERLEVEL-1)) / 256; /* [0, 256] -> [0, DITHERLEVEL-1] */
846   XSetClipMask(dsp, dithergc[n], cp->clip);
847   XSetTSOrigin(dsp, dithergc[n],
848 	       ((kset[cset].obj+cp->obj)->x + cp->ofsx) % DITHERW,
849 	       ((kset[cset].obj+cp->obj)->y + cp->ofsy) % DITHERH);
850   XFillRectangle(dsp, cp->transclip, dithergc[n], 0, 0, cp->width, cp->height);
851   XSetClipMask(dsp, cp->gc, cp->transclip);
852 }
853 
set_initial_transparency()854 void set_initial_transparency()
855 {
856   int i;
857   CELL *cp;
858 
859   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
860     if (cp->width) {
861       cp->transclip = None;
862       if (cp->transparency) {
863 	set_transparency(cp, cp->transparency);
864 	debug_printf("set initial transparency ``%s'' %d\n",
865 		     cp->filename, cp->transparency);
866       }
867     }
868   }
869 }
870 
871 
872 /* make cell clip pixmap */
make_cell_clip(cp)873 Pixmap make_cell_clip(cp)
874      CELL *cp;
875 {
876   int x, y;
877   unsigned long b;
878   int a;
879   int len;
880   unsigned char *ip;
881   Pixmap px;
882 
883   px = XCreatePixmap(dsp, imgwin, cp->width, cp->height, 1);
884   XFillRectangle(dsp, px, bitmapgc0, 0, 0, cp->width, cp->height);
885   ip = cp->image;
886   if (cp->bpp <= 8) {
887     for (y = 0; y < cp->height; y++) {
888       for (x = 0; x < cp->width; x += len) {
889 	b = *ip++;
890 	len = *ip++;
891 	if (b)
892 	  XFillRectangle(dsp, px, bitmapgc1, x, y, len, 1);
893       }
894     }
895   } else {
896     for (x = 0; x < DITHERLEVEL; x++)
897       XSetForeground(dsp, dithergc[x], 1);
898     for (y = 0; y < cp->height; y++) {
899       for (x = 0; x < cp->width; x += len) {
900 	b = get_colorpixel(ip);
901 	ip += 32/8;
902 	len = *ip++;
903 	a = b >> 24;
904 	if (a) {
905 	  if (a == 0xff) {
906 	    XFillRectangle(dsp, px, bitmapgc1, x, y, len, 1);
907 	  } else {
908 	    a += alpha_level;
909 	    if (a < 0) {
910 	      a = 0;
911 	    } else if (a > 0xff) {
912 	      a = 0xff;
913 	    }
914 	    a = (a * DITHERLEVEL) / 256;
915 	    XFillRectangle(dsp, px, dithergc[a], x, y, len, 1);
916 	  }
917 	}
918       }
919     }
920     for (x = 0; x < DITHERLEVEL; x++)
921       XSetForeground(dsp, dithergc[x], 0);
922   }
923 
924   return px;
925 }
926 
make_clip_gc()927 void make_clip_gc()
928 {
929   Pixmap px;
930 
931   px = XCreatePixmap(dsp, imgwin, 1, 1, 1);
932   bitmapgc0 = XCreateGC(dsp, px, 0, 0);
933   XSetForeground(dsp, bitmapgc0, 0);
934   bitmapgc1 = XCreateGC(dsp, px, 0, 0);
935   XSetForeground(dsp, bitmapgc1, 1);
936   XFreePixmap(dsp, px);
937 }
938 
make_clip()939 void make_clip()
940 {
941   int i;
942   CELL *cp;
943 
944   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
945     if (!cp->width)
946       continue;
947     cp->clip = make_cell_clip(cp);
948     XSetClipMask(dsp, cp->gc, cp->clip);
949   }
950 }
951 
952 static int pixel_direct = 0;	/* Calc pixel code from RGB color */
953 static int pixel_shift;
954 static int red_d, red_n, red_m;
955 static int green_d, green_n, green_m;
956 static int blue_d, blue_n, blue_m;
957 
set_gcpixel(b)958 void set_gcpixel(b)
959      unsigned long b;
960 {
961   XColor c;
962   unsigned mask;
963 
964   c.red = ((b>>16) & 0xff) * 0x100;
965   c.green = ((b>>8) & 0xff) * 0x100;
966   c.blue = (b & 0xff) * 0x100;
967   mask = 0xff;
968   while (!XAllocColor(dsp, cmap, &c)) {
969     mask = (mask << 1) | 1;
970     c.red &= ~mask;
971     c.green &= ~mask;
972     c.blue &= ~mask;
973   }
974   XSetForeground(dsp, true_color_gc, c.pixel);
975 }
976 
make_cell_pixmap()977 void make_cell_pixmap()
978 {
979   int i, x, y, len;
980   unsigned long b;
981   unsigned char *ip;
982   CELL *cp;
983   int topcol;
984   unsigned char *skip_pixel;
985 
986   skip_pixel = ks_malloc(colcnt);
987   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
988     if (!cp->width || !cp->setflag[cset] || cp->pixpal == cpal)
989       continue;
990     if (private_color_mode && cp->pixpal >= 0) {
991       cp->pixpal = cpal;
992       continue;
993     }
994     if (cp->bpp <= 8) {
995       /* decide draw skip pixel */
996       bzero(skip_pixel, colcnt);
997       topcol = *(colindex+cp->colfile);
998       skip_pixel[topcol] = 1;	/* transparent pixel */
999       if (cp->pixpal >= 0) {
1000 	for (x = 0; x < colcnt; x++) {
1001 	  if (private_color_mode ||
1002 	      (xcol[cp->pixpal]+x)->pixel == (xcol[cpal]+x)->pixel)
1003 	    skip_pixel[x] = 1;
1004 	}
1005       }
1006       ip = cp->image;
1007       for (y = 0; y < cp->height; y++) {
1008 	for (x = 0; x < cp->width; x += len) {
1009 	  b = *ip++;
1010 	  len = *ip++;
1011 	  if (!skip_pixel[topcol+b])
1012 	    XFillRectangle(dsp, cp->pixmap, *(paint_gc+topcol+b), x, y, len, 1);
1013 	}
1014       }
1015     } else {
1016       ip = cp->image;
1017       if (pixel_direct) {
1018 	if (pixel_shift) {
1019 	  for (y = 0; y < cp->height; y++) {
1020 	    for (x = 0; x < cp->width; x += len) {
1021 	      b = get_colorpixel(ip);
1022 	      ip += 32/8;
1023 	      len = *ip++;
1024 	      b =
1025 		((red_d ? ((b & 0x00ff0000U) << red_n) :
1026 		  ((b & 0x00ff0000U) >> red_n)) & red_m)
1027 		|
1028 		((green_d ? ((b & 0x0000ff00U) << green_n) :
1029 		  ((b & 0x0000ff00U) >> green_n)) & green_m)
1030 		|
1031 		((blue_d ? ((b & 0x000000ffU) << blue_n) :
1032 		  ((b & 0x000000ffU) >> blue_n)) & blue_m)
1033 		;
1034 	      XSetForeground(dsp, true_color_gc, b);
1035 	      XFillRectangle(dsp, cp->pixmap, true_color_gc, x, y, len, 1);
1036 	    }
1037 	  }
1038 	} else {		/* pixel_shift */
1039 	  for (y = 0; y < cp->height; y++) {
1040 	    for (x = 0; x < cp->width; x += len) {
1041 	      b = get_colorpixel(ip);
1042 	      ip += 32/8;
1043 	      len = *ip++;
1044 	      b &= 0x00ffffffU;
1045 	      XSetForeground(dsp, true_color_gc, b);
1046 	      XFillRectangle(dsp, cp->pixmap, true_color_gc, x, y, len, 1);
1047 	    }
1048 	  }
1049 	}
1050       } else {			/* pixel_direct */
1051 	fprintf(stderr, "* %s\n", cp->filename);
1052 	for (y = 0; y < cp->height; y++) {
1053 	  for (x = 0; x < cp->width; x += len) {
1054 	    b = get_colorpixel(ip);
1055 	    ip += 32/8;
1056 	    len = *ip++;
1057 	    set_gcpixel(b);
1058 	    XFillRectangle(dsp, cp->pixmap, true_color_gc, x, y, len, 1);
1059 	  }
1060 	}
1061       }
1062     }
1063     cp->pixpal = cpal;
1064   }
1065   free(skip_pixel);
1066 }
1067 
make_cell_pixmap_image()1068 void make_cell_pixmap_image()
1069 {
1070   int i, j, x, y, len;
1071   unsigned char b, *ip;
1072   CELL *cp;
1073   XImage *image;
1074   char *xip;
1075   XColor *xp;
1076 
1077   image = XCreateImage(dsp, vis,
1078 		       screen_depth, ZPixmap, 0, NULL, imgw, imgh,
1079 		       screen_depth > 8 ? 32 : 8, 0);
1080   if (image == NULL)
1081     msg("E make_cell_pixmap_image create image error!\n");
1082   image->data = ks_malloc(image->bytes_per_line * imgh);
1083   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
1084     if (!cp->width || !cp->setflag[cset] || cp->pixpal == cpal)
1085       continue;
1086     if (private_color_mode && cp->pixpal >= 0) {
1087       cp->pixpal = cpal;
1088       continue;
1089     }
1090     XSetClipOrigin(dsp, cp->gc, 0, 0);
1091     xp = xcol[cpal]+*(colindex+cp->colfile);
1092     ip = cp->image;
1093     xip = image->data;
1094     if (image->bitmap_unit == 8) {
1095       for (y = 0; y < cp->height; y++) {
1096 	for (x = 0; x < cp->width; x += len) {
1097 	  b = *ip++;
1098 	  len = *ip++;
1099 	  if (b)
1100 	    memset(xip+x, (xp+b)->pixel, len);
1101 	}
1102 	xip += image->bytes_per_line;
1103       }
1104     } else {
1105       for (y = 0; y < cp->height; y++) {
1106 	for (x = 0; x < cp->width; x += len) {
1107 	  b = *ip++;
1108 	  len = *ip++;
1109 	  if (b)
1110 	    for (j = 0; j < len; j++)
1111 	      XPutPixel(image, x+j, y, (xp+b)->pixel);
1112 	}
1113 	xip += image->bytes_per_line;
1114       }
1115     }
1116     XPutImage(dsp, cp->pixmap, cp->gc, image,
1117 	      0, 0, 0, 0, cp->width, cp->height);
1118     cp->pixpal = cpal;
1119   }
1120   free(image->data);
1121   XFree(image);
1122 }
1123 
make_world_pixmap()1124 int make_world_pixmap()
1125 {
1126   static Bool world_pixmap_created = False;
1127 
1128   if (world_pixmap_created)
1129     XFreePixmap(dsp, world_pixmap);
1130   world_pixmap = XCreatePixmap(dsp, imgwin, imgw, imgh, screen_depth);
1131   world_pixmap_created = True;
1132   return 0;
1133 }
1134 
expose_image(x,y,w,h)1135 void expose_image(x, y, w, h)
1136      int x;
1137      int y;
1138      int w;
1139      int h;
1140 {
1141   XCopyArea(dsp, world_pixmap, imgwin, imggc, x, y, w, h, x, y);
1142 }
1143 
redraw_cells(x0,y0,w0,h0)1144 void redraw_cells(x0, y0, w0, h0)
1145      int x0;
1146      int y0;
1147      int w0;
1148      int h0;
1149 {
1150   int i;
1151   int x, y, w, h;
1152   int ox, oy;			/* cell left-top position */
1153   int xe, ye;
1154   CELL *p;
1155   OBJPOS *objp;
1156 
1157   /* area limit */
1158   if (x0 < 0) {
1159     w0 += x0;
1160     x0 = 0;
1161   }
1162   if (y0 < 0) {
1163     h0 += y0;
1164     y0 = 0;
1165   }
1166   if (x0 + w0 >= imgw)
1167     w0 = imgw - x0;
1168   if (y0 + h0 >= imgh)
1169     h0 = imgh - y0;
1170   XFillRectangle(dsp, world_pixmap, imggc, x0, y0, w0, h0);
1171   xe = x0 + w0;
1172   ye = y0 + h0;
1173   objp = kset[cset].obj;
1174   for (p = cell+celcnt-1, i = celcnt; i; --p, --i) {
1175     if (p->width && p->setflag[cset] && !p->unmap &&
1176 	(ox = (objp+p->obj)->x + p->ofsx) < xe &&
1177 	ox + p->width >= x0 &&
1178 	(oy = (objp+p->obj)->y + p->ofsy) < ye &&
1179 	oy + p->height >= y0) {
1180       ox = (objp+p->obj)->x + p->ofsx;
1181       oy = (objp+p->obj)->y + p->ofsy;
1182       x = ox > x0 ? ox : x0;
1183       y = oy > y0 ? oy : y0;
1184       w = (ox + p->width < xe) ? ox + p->width - x : xe - x;
1185       h = (oy + p->height < ye) ? oy + p->height - y : ye - y;
1186       XSetClipOrigin(dsp, p->gc, ox, oy);
1187       XCopyArea(dsp, p->pixmap, world_pixmap, p->gc,
1188 		x-ox, y-oy, w, h, x, y);
1189     }
1190   }
1191   /* transfer image to window */
1192   expose_image(x0, y0, w0, h0);
1193 }
1194 
redraw_all_cells()1195 void redraw_all_cells()
1196 {
1197   redraw_cells(0, 0, imgw, imgh);
1198 }
1199 
set_topwin_attributes()1200 void set_topwin_attributes()
1201 {
1202   Pixmap px;
1203 
1204   if (border_color >= colcnt) {
1205     msg("W bad border %d.\n", border_color);
1206     border_color = (colcnt > 0 ? 0 : -1);
1207   }
1208   if (border_color < 0) {
1209     px =
1210       XCreatePixmapFromBitmapData(dsp, viewwin,
1211 				  (char *)hatch_ptrn, 8, 8,
1212 				  BlackPixel(dsp, scr),
1213 				  WhitePixel(dsp, scr),
1214 				  screen_depth);
1215     XSetWindowBackgroundPixmap(dsp, viewwin, px);
1216     XFreePixmap(dsp, px);
1217   } else {
1218     XSetWindowBackground(dsp, viewwin,
1219 			 (xcol[kset[cset].pal]+border_color)->pixel);
1220   }
1221   XSetWindowBackgroundPixmap(dsp, imgwin, None);
1222   XClearWindow(dsp, viewwin);
1223 
1224   if (colcnt > 0) {
1225     XSetForeground(dsp, imggc, (xcol[kset[cset].pal])->pixel);
1226   } else {
1227 #if 0
1228     XSetForeground(dsp, imggc, BlackPixel(dsp, scr));
1229 #else
1230     XSetForeground(dsp, imggc, spx[SPX_BG]);
1231 #endif
1232   }
1233 }
1234 
change_palette(n)1235 void change_palette(n)
1236      int n;
1237 {
1238   int i;
1239   XColor *xp;
1240 
1241   cpal = n;
1242   if (private_color_mode) {
1243     set_private_colorcells(n);
1244     n = 0;
1245   }
1246   if (!image_mode) {
1247     for (xp = xcol[n], i = 0; i < colcnt; xp++, i++) {
1248       XSetForeground(dsp, *(paint_gc+i), xp->pixel);
1249     }
1250   }
1251   set_topwin_attributes();
1252   menu_setpal_change();
1253 }
1254 
init_system_color_name()1255 void init_system_color_name()
1256 {
1257   int i;
1258 
1259   for (i = 0; i < SPX_MAX; i++)
1260     str_color[i] = NULL;
1261 }
1262 
set_system_color_name()1263 void set_system_color_name()
1264 {
1265   int i;
1266   char **p;
1267   static struct {
1268     char *colorname[SPX_MAX];
1269   } spx_color_default[3] = {
1270     {{"#fae0c7", "Black", "#febfbd", "#db975b", "#c0f3a2"}},
1271     {{"White",   "Black", "#e1e1e1", "#9a9a9a", "#eaeaea"}},
1272     {{"White",	 "Black", "Black",   "White",	"White"}}
1273   };
1274 
1275   p = spx_color_default[gray_mode].colorname;
1276   for (i = 0; i < SPX_MAX; i++) {
1277     if (str_color[i] == NULL)
1278       str_color[i] = *p;
1279     p++;
1280   }
1281 }
1282 
setup_system_gc()1283 void setup_system_gc()
1284 {
1285   int i;
1286   static struct {
1287     int bg;
1288     int fg;
1289   } pa[SGC_MAX] = {
1290     {SPX_BG, SPX_FG},		/* SGC_GEN */
1291     {SPX_MN, SPX_FG},		/* SGC_MN */
1292     {SPX_BT, SPX_FG},		/* SGC_BT0 */
1293     {SPX_FG, SPX_BT},		/* SGC_BT1 */
1294     {SPX_BG, SPX_BG2},		/* SGC_IN0 */
1295     {SPX_BG2, SPX_BG},		/* SGC_IN1 */
1296     {SPX_BG, SPX_FG},		/* SGC_T8 */
1297     {SPX_BG, SPX_FG}		/* SGC_T16 */
1298   };
1299 
1300   for (i = 0; i < SGC_MAX; i++) {
1301     XSetBackground(dsp, sysgc[i], spx[pa[i].bg]);
1302     XSetForeground(dsp, sysgc[i], spx[pa[i].fg]);
1303   }
1304 }
1305 
parse_system_colors(p)1306 void parse_system_colors(p)
1307      XColor *p;
1308 {
1309   int i;
1310 
1311   for (i = 0; i < SPX_MAX; i++) {
1312     if (!XParseColor(dsp, cmap, str_color[i], p))
1313       msg("E color ``%s'' unknown!\n", str_color[i]);
1314     p++;
1315   }
1316 }
1317 
alloc_system_colors()1318 void alloc_system_colors()
1319 {
1320   int i;
1321   XColor col[SPX_MAX];
1322 
1323   parse_system_colors(col);
1324   for (i = 0; i < SPX_MAX; i++) {
1325     if (!XAllocColor(dsp, cmap, &col[i])) {
1326       msg("W color ``%s'' allocation miss.\n", str_color[i]);
1327       col[i].pixel =
1328 	col[i].green & 0x8000 ? WhitePixel(dsp, scr) : BlackPixel(dsp, scr);
1329     }
1330     spx[i] = col[i].pixel;
1331   }
1332 }
1333 
pix_shift(dir,n,c,m)1334 void pix_shift(dir, n, c, m)
1335      int *dir;			/* 1:left */
1336      int *n;			/* shift bits */
1337      unsigned long c;		/* cell RGB bit mask */
1338      unsigned long m;		/* display pixel RGB bit mask vis->*_mask */
1339 {
1340   int i;
1341   unsigned long b;
1342 
1343   *dir = (c < m);
1344   if (*dir) {
1345     for (b = c; (b >>= 1); c |= b)
1346       ;
1347     for (i = 0; m > c; i++)
1348       m >>= 1;
1349   } else {
1350     for (b = m; (b >>= 1); m |= b)
1351       ;
1352     for (i = 0; c > m; i++)
1353       c >>= 1;
1354   }
1355   *n = i;
1356 }
1357 
set_rgb_pixel()1358 void set_rgb_pixel()
1359 {
1360   red_m = vis->red_mask;
1361   green_m = vis->green_mask;
1362   blue_m = vis->blue_mask;
1363   pix_shift(&red_d,   &red_n,   0x00ff0000U, red_m);
1364   pix_shift(&green_d, &green_n, 0x0000ff00U, green_m);
1365   pix_shift(&blue_d,  &blue_n,  0x000000ffU, blue_m);
1366   pixel_shift = red_d | red_n | green_d | green_n | blue_d | blue_n;
1367   debug_printf("*pixel_shift %d\n", pixel_shift);
1368   debug_printf("* R %s %2d %08x\n", (red_d?"<<":">>"), red_n, red_m);
1369   debug_printf("* G %s %2d %08x\n", (green_d?"<<":">>"), green_n, green_m);
1370   debug_printf("* B %s %2d %08x\n", (blue_d?"<<":">>"), blue_n, blue_m);
1371 }
1372 
1373 #if 0
1374 void change_visual()
1375 {
1376   Status result;
1377   XVisualInfo v;
1378 
1379   if (XMatchVisualInfo(dsp, scr, screen_depth, TrueColor, &v)) {
1380     fprintf(stderr, "* change TruleColor visual\n");
1381     vis = v.visual;
1382   }
1383 }
1384 #endif
1385 
init_screen()1386 void init_screen()
1387 {
1388   int i;
1389   char *p;
1390 
1391   dsp = XOpenDisplay(str_display);
1392   if (dsp == NULL)
1393     msg("E Cannot open display ``%s''!\n", str_display);
1394 
1395   p = get_server_info();
1396   if (debug_mode || test_mode)
1397     fprintf(stderr, "%s\n", p);
1398   scr = DefaultScreen(dsp);
1399   rootwin = DefaultRootWindow(dsp);
1400   screen_depth = DefaultDepth(dsp, scr);
1401   vis = DefaultVisual(dsp, scr);
1402 #if 0
1403   change_visual();
1404 #endif
1405   if (screen_depth == 1) {
1406     gray_mode = 2;
1407   } else {
1408     switch(vis->class) {
1409     case GrayScale:
1410     case StaticGray:
1411       gray_mode = 1;
1412       break;
1413     case TrueColor:
1414     case DirectColor:
1415       pixel_direct = 1;
1416       set_rgb_pixel();
1417       break;
1418     }
1419   }
1420   cmap = DefaultColormap(dsp, scr);
1421   p = get_visual_info();
1422   if (debug_mode || test_mode)
1423     fprintf(stderr, "%s\n", p);
1424   if (image_mode < 0)
1425     image_mode = screen_depth == 8;
1426   set_system_color_name();
1427   for (i = 0; i < SGC_MAX; i++)
1428     sysgc[i] = XCreateGC(dsp, rootwin, 0, 0);
1429   alloc_system_colors();
1430   setup_system_gc();
1431   if (str_curs_fore == NULL)
1432     str_curs_fore = str_color[SPX_BG];
1433   if (str_curs_back == NULL)
1434     str_curs_back = str_color[SPX_FG];
1435   load_font();
1436   init_cursor();
1437 }
1438 
calc_window_geom(w,h)1439 void calc_window_geom(w, h)
1440      int w;
1441      int h;
1442 {
1443   int menu_total_height;
1444 
1445   topw = w;
1446   toph = h;
1447   menu_total_height = mnh + mnbw*2;
1448   mnw = topw - mnbw*2;
1449   if (menu_mode & 1) {
1450     viewy = 0;
1451     mny = toph - menu_total_height;
1452   } else {
1453     mny = 0;
1454     viewy = menu_total_height;
1455   }
1456   vieww = topw - viewbw*2;
1457   viewh = toph - menu_total_height - viewbw*2;
1458   if (vieww <= 0)
1459     vieww = 1;
1460   if (viewh <= 0)
1461     viewh = 1;
1462   imgw = vieww - imgbw*2;
1463   if (imgw < imgw0)
1464     imgw = imgw0;
1465   imgh = viewh - imgbw*2;
1466   if (imgh < imgh0)
1467     imgh = imgh0;
1468 }
1469 
recenter()1470 void recenter()
1471 {
1472   imgx = (vieww - imgw - imgbw*2)/2;
1473   imgy = (viewh - imgh - imgbw*2)/2;
1474   XMoveWindow(dsp, imgwin, imgx, imgy);
1475 }
1476 
resize_topwin(w,h)1477 void resize_topwin(w, h)
1478      int w;
1479      int h;
1480 {
1481   int oimgw, oimgh;
1482   int ovieww, oviewh;
1483 
1484   ovieww = vieww;
1485   oviewh = viewh;
1486   oimgw = imgw;
1487   oimgh = imgh;
1488   calc_window_geom(w, h);
1489   XMoveResizeWindow(dsp, mnwin, mnx, mny, mnw, mnh);
1490   menu_resize();
1491   XMoveResizeWindow(dsp, viewwin, viewx, viewy, vieww, viewh);
1492   XMoveResizeWindow(dsp, aboutwin, viewx, viewy, vieww, viewh);
1493   if (vieww != ovieww || viewh != oviewh)
1494     recenter();
1495   if (imgw != oimgw || imgh != oimgh) {
1496     make_world_pixmap();
1497     redraw_all_cells();
1498     XResizeWindow(dsp, imgwin, imgw, imgh);
1499   }
1500 }
1501 
set_window_attributes()1502 void set_window_attributes()
1503 {
1504   XSetWindowBorder(dsp, viewwin, spx[SPX_FG]);
1505   XSetWindowBorder(dsp, imgwin, spx[SPX_FG]);
1506 }
1507 
get_window_name()1508 char *get_window_name()
1509 {
1510   static char *p = NULL;
1511   char *buf;
1512 
1513   if (p == NULL) {
1514     p = get_filename(conf_file);
1515     if (strcmp(p, "kiss.cnf") == 0) {
1516       if (arcfilecnt) {
1517 	p = get_filename(*(arcfilelist+arcfilecnt-1));
1518       } else {
1519 	buf = ks_strdup(conf_file);
1520 	p = rindex(buf, '/');
1521 	if (p != NULL) {
1522 	  *p = '\0';
1523 	  p = rindex(buf, '/');
1524 	  if (p != NULL)
1525 	    p++;
1526 	}
1527 	if (p == NULL)
1528 	  p = buf;
1529 	p = ks_strdup(p);
1530 	free(buf);
1531       }
1532     }
1533   }
1534   return p;
1535 }
1536 
1537 static Atom wm_delete_window;
1538 
init_window()1539 void init_window()
1540 {
1541   int i, x, y;
1542   int f;
1543   XSizeHints hint;
1544 
1545   iconw = icon_width;
1546   iconh = icon_height;
1547   iconp = XCreateBitmapFromData(dsp, rootwin, icon_bits, iconw, iconh);
1548   if (iconp == None)
1549     msg("W icon bitmap create missed.\n");
1550   hint.flags = 0;
1551   f = XGeometry(dsp, scr, str_geometry, "",
1552 		1, 1, 1, 0, 0, &x, &y, &topw, &toph);
1553   if (f & WidthValue) {
1554     hint.flags |= USSize;
1555   } else {
1556     topw = imgw0+imgbw*2+viewbw*2;
1557     i = DisplayWidth(dsp, scr) - (topbw*2 + 16);
1558     if (topw > i)
1559       topw = i;
1560   }
1561   if (f & HeightValue) {
1562     hint.flags |= USSize;
1563   } else {
1564     toph = imgh0+imgbw*2+mnh+mnbw*2+viewbw*2;
1565     i = DisplayHeight(dsp, scr) - (topbw*2 + 42);
1566     if (toph > i)
1567       toph = i;
1568   }
1569   if (!(f & XValue))
1570     x = 0;
1571   if (!(f & YValue))
1572     y = 0;
1573   if (test_mode || f & XValue || f & YValue)
1574     hint.flags |= USPosition;
1575   hint.x = x;
1576   hint.y = y;
1577   hint.width = topw;
1578   hint.height = toph;
1579   topwin = XCreateSimpleWindow(dsp, rootwin,
1580 			       x, y, topw, toph, topbw,
1581 			       spx[SPX_FG], spx[SPX_BG]);
1582   XSetStandardProperties(dsp, topwin, get_window_name(),
1583 			 get_window_name(), iconp,
1584 			 oargv, oargc, &hint);
1585   XSelectInput(dsp, topwin, ExposureMask|StructureNotifyMask|KeyPressMask);
1586 
1587   wm_delete_window = XInternAtom(dsp, "WM_DELETE_WINDOW", False);
1588   XSetWMProtocols(dsp, topwin, &wm_delete_window, 1);
1589   debug_printf("wm_delete_window %ld\n", wm_delete_window);
1590 
1591   calc_window_geom(topw, toph);
1592   viewwin = XCreateSimpleWindow(dsp, topwin,
1593 				viewx, viewy, vieww, viewh, viewbw,
1594 				spx[SPX_FG], spx[SPX_BG]);
1595   XSelectInput(dsp, viewwin,
1596 	       ButtonPressMask|ButtonReleaseMask|ButtonMotionMask);
1597   imgwin = XCreateSimpleWindow(dsp, viewwin,
1598 			       imgx, imgy, imgw, imgh, imgbw,
1599 			       spx[SPX_FG], spx[SPX_BG]);
1600   recenter();
1601   XSelectInput(dsp, imgwin,
1602 	       ExposureMask|ButtonPressMask|ButtonReleaseMask|
1603 	       ButtonMotionMask|EnterWindowMask);
1604   imggc = XCreateGC(dsp, imgwin, 0, 0);
1605 
1606   mnwin = XCreateSimpleWindow(dsp, topwin,
1607 			      mnx, mny, mnw, mnh, mnbw,
1608 			      spx[SPX_FG], spx[SPX_MN]);
1609   XSelectInput(dsp, mnwin, ExposureMask|ButtonPressMask);
1610   aboutwin = XCreateSimpleWindow(dsp, topwin,
1611 				 viewx, viewy, vieww, viewh, viewbw,
1612 				 spx[SPX_FG], spx[SPX_BG]);
1613   XSelectInput(dsp, aboutwin, ExposureMask|ButtonPressMask);
1614   set_window_attributes();
1615   set_menu_window_attributes();
1616 }
1617 
get_cell_pixel(p,x,y)1618 int get_cell_pixel(p, x, y)
1619      CELL *p;
1620      int x;
1621      int y;
1622 {
1623   int len;
1624   unsigned long b;
1625   unsigned char *ip;
1626 
1627   ip = p->image;
1628   if (p->bpp <= 8) {
1629     ip += *(p->iline + y);
1630     len = 0;
1631     while (len < p->width) {
1632       b = *ip++;
1633       len += *ip++;
1634       if (len > x)
1635 	return b;		/* pixel code */
1636     }
1637   } else {
1638     ip += *(p->iline + y);
1639     len = 0;
1640     while (len < p->width) {
1641       b = get_colorpixel(ip);
1642       ip += 32/8;
1643       len += *ip++;
1644       if (len > x)
1645 	return b >> 24;		/* alpha channel */
1646     }
1647   }
1648   return 0;
1649 }
1650 
1651 /* get pointed cell number in imgwin */
search_cell(x,y)1652 int search_cell(x, y)
1653      int x;
1654      int y;
1655 {
1656   int i, ox, oy;
1657   CELL *p;
1658 
1659   for (p = cell, i = 0; i < celcnt; p++, i++) {
1660     if (p->setflag[cset] && !p->unmap &&
1661 	(ox = (kset[cset].obj+p->obj)->x + p->ofsx) <= x &&
1662 	x < ox + p->width &&
1663 	(oy = (kset[cset].obj+p->obj)->y + p->ofsy) <= y &&
1664 	y < oy + p->height &&
1665 	get_cell_pixel(p, (x - ox), (y - oy)))
1666       return i;			/* cel number */
1667   }
1668   return -1;			/* Not found! */
1669 }
1670 
move_object2(n,x,y,a)1671 int move_object2(n, x, y, a)
1672      int n;
1673      int x;
1674      int y;
1675      AREA *a;
1676 {
1677   OBJPOS *pp;
1678   OBJECT *op;
1679   CELL *cp;
1680   int i;
1681 
1682   op = object+n;
1683   pp = kset[cset].obj+n;
1684   /* move limit */
1685   if (x + op->width > imgw)
1686     x = imgw - op->width;
1687   if (x < 0)
1688     x = 0;
1689   if (y + op->height > imgh)
1690     y = imgh - op->height;
1691   if (y < 0)
1692     y = 0;
1693   if (pp->x == x && pp->y == y)
1694     return 0;			/* not update */
1695   /* calcurate area for redraw */
1696   if (pp->x < x) {
1697     a->x = pp->x;
1698     a->w = x;
1699   } else {
1700     a->x = x;
1701     a->w = pp->x;
1702   }
1703   if (pp->y < y) {
1704     a->y = pp->y;
1705     a->h = y;
1706   } else {
1707     a->y = y;
1708     a->h = pp->y;
1709   }
1710   a->w += op->width - a->x;
1711   a->h += op->height - a->y;
1712   pp->x = x;
1713   pp->y = y;
1714   if (transparency_mode >= 2) {
1715     for (cp = cell, i = 0; i < celcnt; cp++, i++) {
1716       if (cp->width && cp->obj == n && cp->transparency) {
1717 	set_transparency(cp, cp->transparency);
1718       }
1719     }
1720   }
1721   return 1;			/* update */
1722 }
1723 
move_object(n,x,y)1724 void move_object(n, x, y)
1725      int n;
1726      int x;
1727      int y;
1728 {
1729   OBJECT *op;
1730   AREA ar;
1731 
1732   op = object+n;
1733   /* scroll check */
1734   if (op->width <= vieww) {
1735     if ((x+imgbw) < -imgx) {
1736       scrdx = -imgx - (x+imgbw);
1737       pointer_move = True;
1738     } else if ((x+imgbw) + op->width > -imgx + vieww) {
1739       scrdx = -((x+imgbw) + op->width) + (-imgx + vieww);
1740       pointer_move = True;
1741     }
1742   }
1743   if (op->height <= viewh) {
1744     if ((y+imgbw) < -imgy) {
1745       scrdy = -imgy - (y+imgbw);
1746       pointer_move = True;
1747     } else if ((y+imgbw) + op->height > -imgy + viewh) {
1748       scrdy = -((y+imgbw) + op->height) + (-imgy + viewh);
1749       pointer_move = True;
1750     }
1751   }
1752   if (move_object2(n, x, y, &ar))
1753     redraw_cells(ar.x, ar.y, ar.w, ar.h);
1754 }
1755 
revert_all_object_position()1756 void revert_all_object_position()
1757 {
1758   int i;
1759   OBJPOS *p;
1760 
1761   for (p = kset[cset].obj, i = 0; i < objcnt; p++, i++) {
1762     p->x = p->ox;
1763     p->y = p->oy;
1764   }
1765   redraw_all_cells();
1766 }
1767 
1768 #define OPT_ABBREV_MASK	0x10
1769 #define OPT_FUNC	1
1770 #define OPT_SET_INT	2
1771 #define OPT_GET_INT	3
1772 #define OPT_GET_STR	4
1773 
1774 typedef struct {
1775   char *name;
1776   VOIDPTR parm;
1777   char type;
1778   char setvalue;		/* for OPT_SET_INT */
1779 } OPTION;
1780 
1781 #define OPTTBL(name,type,ptr,val) {(name), (VOIDPTR)(ptr), (type), (val)}
1782 
1783 static OPTION opttbl[] = {
1784   OPTTBL("--version",	OPT_FUNC,	opt_version,		0),
1785   OPTTBL("-V",		OPT_FUNC,	opt_version,		0),
1786   OPTTBL("--help",	OPT_FUNC,	usage,			0),
1787   OPTTBL("-help",	OPT_FUNC,	usage,			0),
1788   OPTTBL("-?",		OPT_FUNC,	usage,			0),
1789   OPTTBL("-t",		OPT_FUNC,	exec_test,		0),
1790   OPTTBL("-nowarncase",	OPT_SET_INT,	&warncase,		0),
1791   OPTTBL("-maxaction",	OPT_FUNC,	set_maxaction,		1),
1792   OPTTBL("-maxtimer",	OPT_FUNC,	set_maxtimer,		1),
1793   OPTTBL("-maxevent",	OPT_FUNC,	set_maxevent,		1),
1794   OPTTBL("-maxsoundfile",OPT_FUNC,	set_maxsoundfile,	1),
1795   OPTTBL("--debug",	OPT_SET_INT,	&debug_mode,		1),
1796   OPTTBL("-debug",	OPT_SET_INT,	&debug_mode,		1),
1797   OPTTBL("-d",		OPT_SET_INT,	&debug_mode,		1),
1798   OPTTBL("-test",	OPT_SET_INT,	&test_mode,		1),
1799   OPTTBL("--silent",	OPT_SET_INT,	&verbose_mode,		0),
1800   OPTTBL("-silent",	OPT_SET_INT,	&verbose_mode,		0),
1801   OPTTBL("--quiet",	OPT_SET_INT,	&verbose_mode,		0),
1802   OPTTBL("--verbose",	OPT_SET_INT,	&verbose_mode,		3),
1803   OPTTBL("-verbose",	OPT_SET_INT,	&verbose_mode,		3),
1804   OPTTBL("-v",		OPT_SET_INT,	&verbose_mode,		3),
1805   OPTTBL("-scroll",	OPT_SET_INT,	&scroll_limit,		0),
1806   OPTTBL("-gray",	OPT_SET_INT,	&gray_mode,		1),
1807   OPTTBL("-mono",	OPT_SET_INT,	&gray_mode,		2),
1808   OPTTBL("-info",	OPT_SET_INT,	&info_mode,		1),
1809   OPTTBL("-s",		OPT_SET_INT,	&cursor_mode,		1),
1810   OPTTBL("-trace",	OPT_SET_INT,	&motion_compress,	0),
1811   OPTTBL("-nosound",	OPT_SET_INT,	&sound_mode,		0),
1812   OPTTBL("-noevent",	OPT_SET_INT,	&event_mode,		0),
1813   OPTTBL("-eventshell",	OPT_SET_INT,	&enable_event_shell,	1),
1814   OPTTBL("-nosleep",	OPT_SET_INT,	&sleep_tick,		0),
1815   OPTTBL("-display",	OPT_GET_STR,	&str_display,		0),
1816   OPTTBL("-geometry",	OPT_GET_STR,	&str_geometry,		0),
1817   OPTTBL("-font",	OPT_GET_STR,	&str_font,		0),
1818   OPTTBL("-font8",	OPT_GET_STR,	&str_font8,		0),
1819   OPTTBL("-font16",	OPT_GET_STR,	&str_font16,		0),
1820   OPTTBL("-fg",		OPT_GET_STR,	&str_color[SPX_FG],	0),
1821   OPTTBL("-bg",		OPT_GET_STR,	&str_color[SPX_BG],	0),
1822   OPTTBL("-bg2",	OPT_GET_STR,	&str_color[SPX_BG2],	0),
1823   OPTTBL("-menucolor",	OPT_GET_STR,	&str_color[SPX_MN],	0),
1824   OPTTBL("-buttoncolor",OPT_GET_STR,	&str_color[SPX_BT],	0),
1825   OPTTBL("-cursorfg",	OPT_GET_STR,	&str_curs_fore,		0),
1826   OPTTBL("-cursorbg",	OPT_GET_STR,	&str_curs_back,		0),
1827   OPTTBL("-evid",	OPT_GET_STR,	&evid,			0),
1828   OPTTBL("-soundcache",	OPT_GET_STR,	&str_sound_cache_limit,	0),
1829   OPTTBL("-esd",	OPT_GET_STR,	&esd_host,		0),
1830   OPTTBL("-noesd",	OPT_SET_INT,	&use_esd,		0),
1831   OPTTBL("-bw",		OPT_GET_INT,	&topbw,			0),
1832   OPTTBL("-viewbw",	OPT_GET_INT,	&viewbw,		0),
1833   OPTTBL("-imagebw",	OPT_GET_INT,	&imgbw,			0),
1834   OPTTBL("-menubw",	OPT_GET_INT,	&mnbw,			0),
1835   OPTTBL("-cursor",	OPT_GET_INT,	&cursor_mode,		0),
1836   OPTTBL("-menu",	OPT_GET_INT,	&menu_mode,		0),
1837   OPTTBL("-fixed",	OPT_GET_INT,	&fixed,			0),
1838   OPTTBL("-unfix",	OPT_GET_INT,	&unfixed,		0),
1839   OPTTBL("-sound",	OPT_GET_INT,	&sound_mode,		0),
1840   OPTTBL("-tick",	OPT_GET_INT,	&sleep_tick,		0),
1841   OPTTBL("-randseed",	OPT_GET_INT,	&randseed,		0),
1842   OPTTBL("-p",		OPT_SET_INT,	&private_color_mode,	1),
1843   OPTTBL("-nocolormap",	OPT_SET_INT,	&private_colormap_mode,	0),
1844   OPTTBL("-u",		OPT_SET_INT,	&objpos_first_align,	1),
1845   OPTTBL("-o",		OPT_SET_INT,	&oldcnf_comaptible,	1),
1846   OPTTBL("-k",		OPT_GET_STR|OPT_ABBREV_MASK,	&hes_keyword,	0),
1847   OPTTBL("-image",	OPT_SET_INT,	&image_mode,		1),
1848   OPTTBL("-noimage",	OPT_SET_INT,	&image_mode,		0),
1849   OPTTBL("-wkiss",	OPT_SET_INT,	&wkiss_bug_emulation,	1),
1850   OPTTBL("-transparency",OPT_GET_INT,	&transparency_mode,	0),
1851   OPTTBL("-comment",	OPT_GET_INT,	&comment_mode,		0),
1852   OPTTBL("-commentline",OPT_SET_INT,	&comment_linenum,	1),
1853   OPTTBL("-commentbw",	OPT_GET_INT,	&combw,			0),
1854   OPTTBL("-button1",	OPT_GET_INT,	&button_func_tbl[1],	0),
1855   OPTTBL("-button2",	OPT_GET_INT,	&button_func_tbl[2],	0),
1856   OPTTBL("-button3",	OPT_GET_INT,	&button_func_tbl[3],	0),
1857   OPTTBL("-document",	OPT_GET_STR,	&doc_command,		0),
1858   OPTTBL("-doc",	OPT_GET_STR,	&doc_command,		0),
1859   OPTTBL("-suffix",	OPT_FUNC,	opt_add_doc_suffix,	1),
1860   OPTTBL("-nosuffix",	OPT_FUNC,	opt_del_doc_suffix,	1),
1861   OPTTBL("-autoadjust",	OPT_GET_INT,	&auto_adjust,		0),
1862   OPTTBL("-alpha",	OPT_GET_INT,	&alpha_level,		0),
1863   OPTTBL("-midiplayer", OPT_GET_STR,    &midi_player,           0),
1864   OPTTBL(NULL,		0,		NULL,			0)
1865 };
1866 
parse_option(ac,av)1867 int parse_option(ac, av)
1868      int *ac;
1869      char ***av;
1870 {
1871   OPTION *p;
1872   int i;
1873   typedef void (*VOIDFUNCPTR)();
1874 
1875   for (p = opttbl; p->name != NULL; p++) {
1876     if (strcmp(**av, p->name) == 0) {
1877       --*ac;
1878       ++*av;
1879       switch(p->type & ~OPT_ABBREV_MASK) {
1880       case OPT_FUNC:
1881 	if (p->setvalue) {
1882 	  if (*ac) {
1883 	    ((VOIDFUNCPTR)(p->parm))(**av);
1884 	    ++*av;
1885 	    --*ac;
1886 	  }
1887 	} else {
1888 	  ((VOIDFUNCPTR)(p->parm))();
1889 	}
1890 	break;
1891       case OPT_SET_INT:
1892 	*((int *)(p->parm)) = p->setvalue;
1893 	break;
1894       case OPT_GET_INT:
1895 	if (*ac) {
1896 	  *((int *)(p->parm)) = strtol(**av, NULL, 0);
1897 	  ++*av;
1898 	  --*ac;
1899 	}
1900 	break;
1901       case OPT_GET_STR:
1902 	if (*ac) {
1903 	  *((char **)(p->parm)) = **av;
1904 	  ++*av;
1905 	  --*ac;
1906 	}
1907 	break;
1908       }
1909       return 0;
1910     } else if (p->type & OPT_ABBREV_MASK &&
1911 	       strncmp(**av, p->name, i = strlen(p->name)) == 0) {
1912       switch(p->type & ~OPT_ABBREV_MASK) {
1913       case OPT_GET_INT:
1914 	*((int *)(p->parm)) = strtol(**av+i, NULL, 0);
1915 	break;
1916       case OPT_GET_STR:
1917 	*((char **)(p->parm)) = **av+i;
1918 	break;
1919       }
1920       ++*av;
1921       --*ac;
1922       return 0;
1923     }
1924   }
1925   return 1;
1926 }
1927 
get_archive_type(name)1928 ARTBL *get_archive_type(name)
1929      char *name;
1930 {
1931   ARTBL *p;
1932 
1933   for (p = artype; p->suffix != NULL; p++)
1934     if (is_suffix(name, p->suffix))
1935       return p;
1936   return NULL;
1937 }
1938 
quote_filename(p)1939 char *quote_filename(p)
1940      char *p;
1941 {
1942   LSTR work;
1943 
1944   lstr_init(&work);
1945   while (*p) {
1946     switch (*p) {
1947     case ';':
1948     case '&':
1949     case '(':
1950     case ')':
1951     case '`':
1952     case '\'':
1953     case '"':
1954       lstr_ch(&work, '\\');
1955       /* FALL THROUGH */
1956     default:
1957       lstr_ch(&work, *p);
1958       break;
1959     }
1960     p++;
1961   }
1962   return work.buf;
1963 }
1964 
gen_arcommand(form,name,file)1965 char *gen_arcommand(form, name, file)
1966      char *form;		/* format template */
1967      char *name;		/* archive file */
1968      char **file;		/* file list */
1969 {
1970   int i;
1971   char *p;
1972   LSTR s;
1973   char *p2;
1974   char **rbuf;
1975   char *prefix;
1976   char *replace_str[2];
1977 
1978   lstr_init(&s);
1979   for (p = form; *p != '\0'; p++) {
1980     if (*p == '%') {
1981       prefix = replace_str[0] = replace_str[1] = NULL;
1982       rbuf = replace_str;
1983       switch(*++p) {
1984       case '%':			/* %% : '%' itself */
1985 	*rbuf = "%";
1986 	break;
1987       case 'P':			/* %P : "name/file[0] ... name/file[n]" */
1988 	prefix = name;
1989 	/* FALL THROUGH */
1990       case 'F':			/* %F : "file[0] ... file[n]" */
1991 	rbuf = file;
1992 	break;
1993       case 'A':			/* %A : "name" (archive file) */
1994 	*rbuf = name;
1995 	break;
1996       case 'D':			/* %D : target directory */
1997 	*rbuf = extract_dir;
1998 	break;
1999       case 'K':			/* %K : hesper keyword */
2000 	*rbuf = hes_keyword;
2001 	break;
2002       default:
2003 	msg("E ``%s'' bad archiver command!\n", form);
2004 	/* NOT REACHED */
2005       }
2006       for (i = 0; *(rbuf+i) != NULL; i++) {
2007 	if (i)
2008 	  lstr_cat(&s, " ");
2009 	if (prefix != NULL) {
2010 	  lstr_cat(&s, prefix);
2011 	  if (*(prefix + strlen(prefix) - 1) != '/')
2012 	    lstr_cat(&s, "/");
2013 	}
2014 	p2 = quote_filename(*(rbuf+i));
2015 	lstr_cat(&s, p2);
2016 	free(p2);
2017       }
2018     } else {
2019       lstr_ch(&s, *p);
2020     }
2021   }
2022   return s.buf;
2023 }
2024 
extract_archive(name)2025 int extract_archive(name)
2026      char *name;		/* archive file */
2027 {
2028   int r;
2029   char *buf;
2030   char *cmd;
2031   ARTBL *p;
2032 
2033   if (!is_regular_file(name))
2034     msg("E archive ``%s'' not found!\n", name);
2035   if (extract_dir == NULL) {
2036     buf = ks_malloc(strlen(tmpdir) + 32);
2037     sprintf(buf, "%s/fkiss%d", tmpdir, (int)getpid());
2038     extract_dir = ks_strdup(buf);
2039     buf = ks_realloc(buf, 6 + strlen(extract_dir) + 1);
2040     sprintf(buf, "mkdir %s", extract_dir);
2041     ks_system(buf);
2042     free(buf);
2043   }
2044   p = get_archive_type(name);
2045   if (p == NULL)
2046     return -1;
2047   cmd = gen_arcommand(p->command, name, NULL);
2048   r = ks_system2(cmd);
2049   free(cmd);
2050   return r;
2051 }
2052 
2053 /* return number of extracted archive */
extract_arc_in_arc()2054 int extract_arc_in_arc()
2055 {
2056   int r;
2057   char **p;
2058   char **list;
2059   char *buf;
2060 
2061   r = 0;
2062   if (extract_dir == NULL)
2063     return 0;
2064   debug_printf("extract_arc_in_arc extract_dir ``%s''\n", extract_dir);
2065   list = dir_ls(extract_dir, NULL);
2066   if (list != NULL) {
2067     for (p = list; *p != NULL; p++) {
2068       buf = ks_malloc(strlen(extract_dir) + 1 + strlen(*p) + 1);
2069       sprintf(buf, "%s/%s", extract_dir, *p);
2070       if (get_archive_type(buf) != NULL) {
2071 	if (extract_archive(buf) == 0)
2072 	  r++;
2073 	unlink(buf);
2074       }
2075       free(buf);
2076     }
2077     dir_free(list);
2078   }
2079   return r;
2080 }
2081 
extract_archives(list,n)2082 int extract_archives(list, n)
2083      char **list;		/* archive file list */
2084      int n;			/* number of files */
2085 {
2086   int r;
2087 
2088   for (r = 0; r < n && get_archive_type(*list) != NULL; r++)
2089     extract_archive(*list++);
2090   while (extract_arc_in_arc())
2091     ;
2092   return r;
2093 }
2094 
image_scroll()2095 void image_scroll()
2096 {
2097   if (scroll_limit) {
2098     if (scrdx > 0 && imgx + scrdx > 0)
2099       scrdx = - imgx;
2100     if (scrdx < 0 && imgx + scrdx + imgw + imgbw*2 < vieww)
2101       scrdx = vieww - (imgx + imgw + imgbw*2);
2102     if (scrdy > 0 && imgy + scrdy > 0)
2103       scrdy = - imgy;
2104     if (scrdy < 0 && imgy + scrdy + imgh + imgbw*2 < viewh)
2105       scrdy = viewh - (imgy + imgh + imgbw*2);
2106   }
2107   if (scrdx || scrdy) {
2108     imgx += scrdx;
2109     imgy += scrdy;
2110     if (pointer_move) {
2111       XWarpPointer(dsp, None, None, 0, 0, 0, 0, scrdx, scrdy);
2112       pointer_move = False;
2113     }
2114     XMoveWindow(dsp, imgwin, imgx, imgy);
2115     scrdx = scrdy = 0;
2116   }
2117 }
2118 
redraw_all()2119 void redraw_all()
2120 {
2121   change_palette(kset[cset].pal);
2122   if (image_mode)
2123     make_cell_pixmap_image();
2124   else
2125     make_cell_pixmap();
2126   redraw_all_cells();
2127 }
2128 
free_system_colors()2129 void free_system_colors()
2130 {
2131   int i;
2132   unsigned long pixels[SPX_MAX];
2133 
2134   if (pixel_direct)
2135     return;
2136   for (i = 0; i < SPX_MAX; i++)
2137     pixels[i] = spx[i];
2138   XFreeColors(dsp, cmap, pixels, SPX_MAX, 0);
2139 }
2140 
set_system_pixels()2141 void set_system_pixels()
2142 {
2143   setup_system_gc();
2144   set_window_attributes();
2145   set_menu_window_attributes();
2146 }
2147 
poor_system_pixels()2148 void poor_system_pixels()
2149 {
2150   free_system_colors();
2151   gray_mode = 2;
2152   init_system_color_name();
2153   set_system_color_name();
2154   alloc_system_colors();
2155   set_system_pixels();
2156   str_curs_fore = "White";
2157   str_curs_back = "Black";
2158   init_cursor();
2159 }
2160 
initialize_main1()2161 int initialize_main1()
2162 {
2163   int i;
2164   char *p;
2165 
2166   /**/
2167   read_directory();
2168   if (read_config(conf_file))
2169     return 1;			/* cnf read error! */
2170   if (cset < 0)
2171     return 1;			/* No effective set! */
2172   if (read_colors())
2173     return 1;
2174   if (read_cells())
2175     return 1;
2176   free_directory();
2177   p = get_cell_info();
2178   if (debug_mode || test_mode)
2179     fprintf(stderr, "%s\n", p);
2180 
2181   if (true_color_cell && !pixel_direct) {
2182     msg("E Visual TrueColor or DirectColor needed to display true color cell!\n");
2183   }
2184 
2185   init_window();
2186   debug_printf("image_mode = %d\n", image_mode);
2187 
2188   for (i = 0; i < MAXPAL; i++) {
2189     xcol[i] = (XColor *)ks_malloc(sizeof(XColor)*colcnt);
2190   }
2191   if (!image_mode) {
2192     paint_gc = (GC *)ks_malloc(sizeof(GC) * colcnt);
2193     for (i = 0; i < colcnt; i++)
2194       *(paint_gc+i) = XCreateGC(dsp, imgwin, 0, 0);
2195     true_color_gc = XCreateGC(dsp, imgwin, 0, 0);
2196   }
2197 
2198   debug_printf("colcnt %d, palcnt %d\n", colcnt, palcnt);
2199   if (alloc_colors())
2200     return 1;
2201   for (i = 0; i < MAXPAL; i++) {
2202     free(kcol[i]);
2203     kcol[i] = NULL;
2204   }
2205   set_topwin_attributes();
2206   make_world_pixmap();
2207   create_cell_pixmap();
2208   create_set_menu();
2209   make_clip_gc();
2210   if (transparency_mode) {
2211     make_transparency_dither();
2212   }
2213   make_clip();
2214   if (transparency_mode) {
2215     set_initial_transparency();
2216   }
2217   redraw_all();
2218   XMapRaised(dsp, topwin);
2219   XMapRaised(dsp, viewwin);
2220   XMapRaised(dsp, imgwin);
2221   return 0;
2222 }
2223 
change_setpal(s,p)2224 int change_setpal(s, p)
2225      int s;
2226      int p;
2227 {
2228   int set_changed, pal_changed;	/* quick and darty hack */
2229   static int nest = 0;
2230 
2231   if (s < 0 || s >= setcnt || !active_set[s])
2232     s = cset;
2233   if (p < 0 || p >= palcnt)
2234     p = kset[s].pal;
2235   if (s == cset && p == kset[cset].pal)
2236     return 0;			/* not changed */
2237   set_changed = pal_changed = 0;
2238   if (cset != s) {
2239     cset = s;
2240     set_changed = 1;
2241   }
2242   if (kset[cset].pal != p) {
2243     kset[cset].pal = p;
2244     pal_changed = 1;
2245   }
2246   debug_printf("set = %d, pal = %d\n", cset, kset[cset].pal);
2247   nest++;
2248   if (set_changed)
2249     kissevent_handler(EVE_SET, s);
2250   if (pal_changed)
2251     kissevent_handler(EVE_COL, p);
2252   if (!--nest)
2253     redraw_all();
2254   return 1;			/* changed */
2255 }
2256 
kiss_iconify()2257 void kiss_iconify()
2258 {
2259   XIconifyWindow(dsp,topwin,scr);
2260 }
2261 
alternate_cell_mapping()2262 void alternate_cell_mapping()
2263 {
2264   if (mapping_changed_cell >= 0) {
2265     change_cel_mapping(cell+mapping_changed_cell, ACT_ALTMAP);
2266   }
2267 }
2268 
next_set(d)2269 int next_set(d)
2270      int d;			/* direction -1:previous 1:next */
2271 {
2272   int i;
2273 
2274   i = cset;
2275   while ((i += d) >= 0 && i < MAXSET) {
2276     if (active_set[i])
2277       return i;
2278   }
2279   return cset;
2280 }
2281 
match_doc(name)2282 int match_doc(name)
2283      char *name;
2284 {
2285   char **p;
2286 
2287   for (p = doc_suffix; *p; p++) {
2288     if (!is_free_doc_suffix(*p)) {
2289       if (is_suffix(name, *p)) {
2290 	return 1;
2291       }
2292     }
2293   }
2294   return 0;
2295 }
2296 
2297 
browse_document()2298 int browse_document()
2299 {
2300   int r;
2301   char **filelist;
2302   char *cmd, *doc_dir, *cmd0;
2303   Window cw, rw;
2304   int wx, wy, rx, ry;
2305   unsigned keys_buttons;
2306   char buf[32];
2307   static char *selectfile[2] = {NULL, NULL};
2308 
2309   doc_dir = (extract_dir != NULL) ? extract_dir : conf_dir;
2310   filelist = dir_ls(doc_dir, match_doc);
2311   cmd = NULL;
2312   cmd0 = ks_strdup(doc_command);
2313   if (index(cmd0, '%') == NULL) {
2314     cmd0 = ks_strdup(cmd0, strlen(cmd0) + 4);
2315     strcat(cmd0, " %P");
2316   }
2317   if (*(cmd0 + strlen(cmd0) - 1) != '&') {
2318     cmd0 = ks_realloc(cmd0, strlen(cmd0) + 2);
2319     strcat(cmd0, "&");
2320   }
2321   XQueryPointer(dsp, rootwin, &rw, &cw, &rx, &ry, &wx, &wy, &keys_buttons);
2322   sprintf(buf, "%+d%+d", rx, ry);
2323   if ((r = select_menu("fkiss doc", buf, filelist)) >= 0) {
2324     selectfile[0] = *(filelist+r);
2325     cmd = gen_arcommand(cmd0, doc_dir, selectfile);
2326   }
2327   free(cmd0);
2328   dir_free(filelist);
2329   if (cmd != NULL) {
2330     ks_system2 (cmd);
2331     free (cmd);
2332   }
2333   return 0;
2334 }
2335 
key_event(p)2336 void key_event(p)
2337      XKeyEvent *p;
2338 {
2339   int i, s;
2340   int keycode;
2341   KeySym key;
2342   XComposeStatus cs;
2343   char buf[32];
2344   static int change_col_mode = 0;
2345 
2346   i = XLookupString(p, buf, sizeof(buf)-1, &key, &cs);
2347   buf[i] = '\0';
2348   /* I don't use switch(key), because key is not int. */
2349   if (key == XK_Left)
2350     keycode = 'h';
2351   else if (key == XK_Right)
2352     keycode = 'l';
2353   else if (key == XK_Down)
2354     keycode = 'j';
2355   else if (key == XK_Up)
2356     keycode = 'k';
2357   else
2358     keycode = buf[0];
2359   s = -1;
2360   switch(keycode) {
2361   case '0':
2362   case '1':
2363   case '2':
2364   case '3':
2365   case '4':
2366   case '5':
2367   case '6':
2368   case '7':
2369   case '8':
2370   case '9':
2371     s = keycode - '0';		/* for ASCII and EBCDIC character set only */
2372     break;
2373   case '-':
2374     change_setpal(next_set(-1), -1);
2375     break;
2376   case '^':
2377   case '=':
2378     change_setpal(next_set(1), -1);
2379     break;
2380   case '[':
2381     change_setpal(-1, kset[cset].pal-1);
2382     break;
2383   case ']':
2384     change_setpal(-1, kset[cset].pal+1);
2385     break;
2386   case 'j':
2387     scrdy = -16;
2388     break;
2389   case 'J':
2390     scrdy = -1;
2391     break;
2392   case 'k':
2393     scrdy = 16;
2394     break;
2395   case 'K':
2396     scrdy = 1;
2397     break;
2398   case 'h':
2399     scrdx = 16;
2400     break;
2401   case 'H':
2402     scrdx = 1;
2403     break;
2404   case 'l':
2405     scrdx = -16;
2406     break;
2407   case 'L':
2408     scrdx = -1;
2409     break;
2410   case ' ':
2411     menu_mode ^= 1;
2412     resize_topwin(topw, toph);
2413     break;
2414   case 'L'-0x40:
2415     recenter();
2416     break;
2417   case 's':
2418     change_col_mode = 0;
2419     break;
2420   case 'c':
2421     change_col_mode = 1;
2422     break;
2423   case 'm':
2424     motion_compress = !motion_compress;
2425     XClearArea(dsp, aboutwin, 0, 0, 0, 0, True);
2426     break;
2427   case 'i':
2428     info_mode = !info_mode;
2429     break;
2430   case '?':
2431     change_menu_func(0);	/* About */
2432     break;
2433   case 'S'-0x40:		/* ^S Save cnf file */
2434     save_config(conf_file);
2435     break;
2436   case 'v':			/* alternate cel map/unmap */
2437     alternate_cell_mapping();
2438     break;
2439   case 0x1b:
2440     kiss_iconify();
2441     break;
2442   case 'q':
2443     change_menu_func(1);	/* Quit */
2444     break;
2445   case 'd':
2446     browse_document();
2447     break;
2448   case 'r':
2449     if (!event_detect)
2450       revert_all_object_position();
2451     break;
2452   }
2453   if (s >= 0) {
2454     if (change_col_mode)
2455       change_setpal(-1, s);
2456     else
2457       change_setpal(s, -1);
2458   }
2459 }
2460 
disp_info()2461 void disp_info()
2462 {
2463   XClearArea(dsp, infowin, 0, 0, 0, 0, True);
2464   XMapWindow(dsp, infowin);
2465 }
2466 
disp_pesi()2467 void disp_pesi()
2468 {
2469   CELL *p;
2470 
2471   p = cell+catched_cell;
2472   strcpy(infostr0, "Pointed: ");
2473   sprintf(infostr, "%s (%d,%d) %d/(%d,%d)",
2474 	  p->filename, catched_cell, p->obj,
2475 	  (object + p->obj)->pesi + pesi_count,
2476 	  p->fix, (object + p->obj)->fix);
2477   if (info_mode)
2478     disp_info();
2479 }
2480 
2481 EVHITWK mouse_move_hit;
2482 int moving_object = -1;
2483 
celhitovl(c0,x0,y0,c1,x1,y1,w,h)2484 int celhitovl(c0, x0, y0, c1, x1, y1, w, h)
2485      CELL *c0;
2486      int x0;
2487      int y0;
2488      CELL *c1;
2489      int x1;
2490      int y1;
2491      int w;
2492      int h;
2493 {
2494   int x, y;
2495 
2496   for (y = 0; y < h; y++) {
2497     for (x = 0; x < w; x++) {
2498       if (get_cell_pixel(c0, x0+x, y0+y) &&
2499 	  get_cell_pixel(c1, x1+x, y1+y)) {
2500 	return 1;
2501       }
2502     }
2503   }
2504   return 0;
2505 }
2506 
celhit1(cp,objx,objy,n)2507 int celhit1(cp, objx, objy, n)
2508      CELL *cp;
2509      int objx;
2510      int objy;
2511      int n;
2512 {
2513   int x0, y0, w0, h0;
2514   int x1, y1, w1, h1;
2515   int x2, y2, w2, h2;
2516   CELL *p;
2517 
2518   p = cell + n;
2519 
2520   if (!cp->setflag[cset] || cp->unmap || !p->setflag[cset] || p->unmap)
2521     return 0;
2522 
2523   x0 = objx + cp->ofsx;
2524   y0 = objy + cp->ofsy;
2525   w0 = cp->width;
2526   h0 = cp->height;
2527 
2528   x1 = (kset[cset].obj + p->obj)->x + p->ofsx;
2529   y1 = (kset[cset].obj + p->obj)->y + p->ofsy;
2530   w1 = p->width;
2531   h1 = p->height;
2532 
2533   x2 = x0 > x1 ? x0 : x1;
2534   w2 = ((x0 + w0 < x1 + w1) ? x0 + w0 : x1 + w1) - x2;
2535   y2 = y0 > y1 ? y0 : y1;
2536   h2 = ((y0 + h0 < y1 + h1) ? y0 + h0 : y1 + h1) - y2;
2537 
2538   if (w2 <= 0 || h2 <= 0)
2539     return 0;			/* None overlap rect region */
2540 
2541   return celhitovl(cp, x2-x0, y2-y0, p, x2-x1, y2-y1, w2, h2);
2542 }
2543 
2544 
check_cell_hit_before(objn)2545 void check_cell_hit_before(objn)
2546      int objn;
2547 {
2548   CELL *cp;
2549   int i, j;
2550   int objx, objy;
2551 
2552   objx = (kset[cset].obj + objn)->x;
2553   objy = (kset[cset].obj + objn)->y;
2554   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
2555     if (cp->obj == objn) {
2556       for (j = 0; j < cp->hitn; j++) {
2557 	(cp->hitp+j)->s = celhit1(cp, objx, objy, (cp->hitp+j)->n);
2558       }
2559     }
2560   }
2561 }
2562 
check_cell_hit_after(objn)2563 void check_cell_hit_after(objn)
2564      int objn;
2565 {
2566   CELL *cp;
2567   int i, j;
2568   int objx, objy;
2569   int before, after;
2570 
2571   objx = (kset[cset].obj + objn)->x;
2572   objy = (kset[cset].obj + objn)->y;
2573   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
2574     if (cp->obj == objn) {
2575       for (j = 0; j < cp->hitn; j++) {
2576 
2577 	before = (cp->hitp+j)->s;
2578 	after = celhit1(cp, objx, objy, (cp->hitp+j)->n);
2579 	if (!before && after) {
2580 	  kissevent_handler2(EVE_COLLIDE, i, (cp->hitp+j)->n);
2581 	}
2582 	if (before && !after) {
2583 	  kissevent_handler2(EVE_APART, i, (cp->hitp+j)->n);
2584 	}
2585       }
2586     }
2587   }
2588 }
2589 
check_obj_hit_cel(cp,objx,objy,o2)2590 int check_obj_hit_cel(cp, objx, objy, o2)
2591      CELL *cp;
2592      int objx;
2593      int objy;
2594      int o2;
2595 {
2596   CELL *p;
2597   int i;
2598   int x0, y0, x1, y1;
2599   int x2, y2;
2600   OBJPOS *pp;
2601 
2602   pp = kset[cset].obj + cp->obj;
2603   x0 = objx + cp->orgx;
2604   y0 = objy + cp->orgy;
2605   x1 = x0 + cp->orgw;
2606   y1 = y0 + cp->orgh;
2607 
2608   pp = kset[cset].obj + o2;
2609   x2 = pp->x;
2610   y2 = pp->y;
2611   for (p = cell, i = 0; i < celcnt; p++, i++) {
2612     if (p->obj == o2 && p->setflag[cset] && !p->unmap) {
2613       if (x0 < x2 + p->orgx + p->orgw && x2 + p->orgx < x1 &&
2614 	  y0 < y2 + p->orgy + p->orgh && y2 + p->orgy < y1) {
2615 	return 1;
2616       }
2617     }
2618   }
2619   return 0;
2620 }
2621 
check_obj_hit1(o1,objx,objy,o2)2622 int check_obj_hit1(o1, objx, objy, o2)
2623      int o1;
2624      int objx;
2625      int objy;
2626      int o2;
2627 {
2628   int i;
2629   CELL *cp;
2630 
2631   for (cp = cell, i = 0; i < celcnt; cp++, i++) {
2632     if (cp->obj == o1 && cp->setflag[cset] && !cp->unmap) {
2633       if (check_obj_hit_cel(cp, objx, objy, o2))
2634 	return 1;
2635     }
2636   }
2637   return 0;
2638 }
2639 
check_obj_hit_before(objn)2640 void check_obj_hit_before(objn)
2641      int objn;
2642 {
2643   OBJECT *op;
2644   int i;
2645   int o1, o2;
2646   int objx, objy;
2647 
2648   o1 = objn;
2649   op = object + o1;
2650   for (i = 0; i < op->ohitn; i++) {
2651     o2 = (op->ohitp + i)->n;
2652     objx = (kset[cset].obj + o1)->x;
2653     objy = (kset[cset].obj + o1)->y;
2654     (op->ohitp + i)->s = check_obj_hit1(o1, objx, objy, o2);
2655   }
2656 }
2657 
check_obj_hit_after(objn)2658 void check_obj_hit_after(objn)
2659      int objn;
2660 {
2661   OBJECT *op;
2662   int i;
2663   int o1, o2;
2664   int objx, objy;
2665   int before, after;
2666 
2667   o1 = objn;
2668   op = object + o1;
2669   for (i = 0; i < op->ohitn; i++) {
2670     o2 = (op->ohitp + i)->n;
2671 
2672     before = (op->ohitp + i)->s;
2673 
2674     objx = (kset[cset].obj + o1)->x;
2675     objy = (kset[cset].obj + o1)->y;
2676     after = check_obj_hit1(o1, objx, objy, o2);
2677 
2678     if (after) {
2679       if (!before)
2680 	kissevent_handler2(EVE_IN, o1, o2);
2681       kissevent_handler2(EVE_STILLIN, o1, o2);
2682     } else {
2683       if (before)
2684 	kissevent_handler2(EVE_OUT, o1, o2);
2685       kissevent_handler2(EVE_STILLOUT, o1, o2);
2686     }
2687   }
2688 }
2689 
2690 
move_object_start(p,n)2691 void move_object_start(p, n)
2692      EVHITWK *p;
2693      int n;
2694 {
2695   p->objn = n;
2696   p->objx = (kset[cset].obj + n)->x;
2697   p->objy = (kset[cset].obj + n)->y;
2698   check_cell_hit_before(n);
2699   check_obj_hit_before(n);
2700 }
2701 
move_object_end(p)2702 void move_object_end(p)
2703      EVHITWK *p;
2704 {
2705   OBJPOS *pp;
2706 
2707   pp = kset[cset].obj + p->objn;
2708   check_cell_hit_after(p->objn);
2709   check_obj_hit_after(p->objn);
2710 }
2711 
catch_check(x,y)2712 void catch_check(x, y)
2713      int x;
2714      int y;
2715 {
2716   CELL *p;
2717 
2718   catched_cell = search_cell(x, y);
2719   catched_cell2 = catched_cell;
2720   if (catched_cell >= 0) {
2721     pesi_count = 0;		/* pesi-pesi start */
2722     disp_pesi();
2723     p = cell+catched_cell;
2724     if ((object + p->obj)->fix >= fixed)
2725       catched_cell = -1;
2726     catched_objx = (kset[cset].obj+p->obj)->x;
2727     catched_objy = (kset[cset].obj+p->obj)->y;
2728     catched_dx = x - (catched_objx + p->ofsx);
2729     catched_dy = y - (catched_objy + p->ofsy);
2730   }
2731   if (catched_cell >= 0) {
2732     moving_object = (cell+catched_cell)->obj;
2733     move_object_start(&mouse_move_hit, (cell+catched_cell)->obj);
2734   }
2735 }
2736 
update_pesi(p)2737 void update_pesi(p)
2738      OBJECT *p;
2739 {
2740   int i;
2741 
2742   i = p->pesi + pesi_count;
2743   if (i > p->fix)
2744     i = p->fix;
2745   p->pesi = i;
2746   pesi_count = 0;
2747 }
2748 
adjust_pos()2749 void adjust_pos()
2750 {
2751   OBJPOS *p;
2752   int x, y, d, d0, s, n;
2753 
2754   if (!auto_adjust)
2755     return;
2756   d0 = auto_adjust * 2;
2757   n = -1;
2758   for (s = 0; s < setcnt; s++) {
2759     if (active_set[s]) {
2760       p = kset[s].obj + mobjn;
2761       x = mobjx - p->ox;
2762       y = mobjy - p->oy;
2763       if (x >= -auto_adjust && x <= auto_adjust &&
2764 	  y >= -auto_adjust && y <= auto_adjust) {
2765 	d = (x < 0 ? -x : x) + (y < 0 ? -y : y);
2766 	if (d < d0) {
2767 	  d0 = d;
2768 	  n = s;
2769 	}
2770       }
2771     }
2772   }
2773   if (n < 0)
2774     return;
2775   p = kset[n].obj + mobjn;
2776   mobjx = p->ox;
2777   mobjy = p->oy;
2778 }
2779 
release_object()2780 void release_object()
2781 {
2782   OBJECT *p;
2783   AREA ar;
2784 
2785   if (mobjn >= 0) {
2786     adjust_pos();
2787     p = object + mobjn;
2788     if (p->pesi < p->fix) {
2789       /* return last position */
2790       mobjx = catched_objx;
2791       mobjy = catched_objy;
2792       kissevent_handler(EVE_FIXDROP, catched_cell);
2793     }
2794     kissevent_handler(EVE_DROP, catched_cell);
2795 
2796     if (move_object2(mobjn, mobjx, mobjy, &ar))
2797       redraw_cells(ar.x, ar.y, ar.w, ar.h);
2798 
2799     mobjn = -1;
2800     moving_object = -1;
2801     move_object_end(&mouse_move_hit);
2802   }
2803   catched_cell = -1;
2804   XUnmapWindow(dsp, infowin);
2805 }
2806 
pesi_pesi()2807 void pesi_pesi()
2808 {
2809   int move_limit, pesi_limit;
2810   OBJECT *p;
2811 
2812   p = object + (cell+catched_cell)->obj;
2813   if (p->pesi >= p->fix)
2814     return;
2815   pesi_limit = p->pesi/20 + 1;
2816   move_limit = ((p->pesi + pesi_limit) * 16) / p->fix + 1;
2817   ++pesi_count;
2818   if (mobjx < catched_objx - move_limit) {
2819     mobjx = catched_objx - move_limit;
2820     pesi_count = pesi_limit;
2821   } else if (mobjx > catched_objx + move_limit) {
2822     mobjx = catched_objx + move_limit;
2823     pesi_count = pesi_limit;
2824   }
2825   if (mobjy < catched_objy - move_limit) {
2826     mobjy = catched_objy - move_limit;
2827     pesi_count = pesi_limit;
2828   } else if (mobjy > catched_objy + move_limit) {
2829     mobjy = catched_objy + move_limit;
2830     pesi_count = pesi_limit;
2831   }
2832   disp_pesi();
2833   if (pesi_count >= pesi_limit) {
2834     pesi_count = pesi_limit;
2835     update_pesi(p);
2836     if (p->pesi < p->fix && p->pesi < unfixed) {
2837       /* return original position */
2838       /* move_object(mobjn, mobjx, mobjy); */
2839       cursor_hand();
2840       release_object();
2841     } else {
2842       /* without this the object must be dragged against a resistance */
2843       p->pesi = p->fix;
2844       /* unfixed! free moving! */
2845       kissevent_handler(EVE_UNFIX, catched_cell);
2846     }
2847   }
2848 }
2849 
move_check(x,y)2850 void move_check(x, y)
2851      int x;
2852      int y;
2853 {
2854   CELL *p;
2855 
2856   if (catched_cell >= 0) {
2857     p = cell+catched_cell;
2858     mobjn = p->obj;
2859     mobjx = x - catched_dx - p->ofsx;
2860     mobjy = y - catched_dy - p->ofsy;
2861     pesi_pesi();
2862   } else if (catched_cell == -2) {
2863     if (!scrdx && !scrdy) {
2864       scrdx = x - catch_x;
2865       scrdy = y - catch_y;
2866     }
2867   }
2868 }
2869 
2870 /* startup initialize
2871  * called before parse options
2872  */
init0()2873 void init0()
2874 {
2875   int i;
2876   char *p;
2877 
2878   /* all set active */
2879   for (i = 0; i < MAXSET; i++)
2880     active_set[i] = 1;
2881   init_system_color_name();
2882   p = getenv("TMPDIR");
2883   if (p != NULL)
2884     tmpdir = p;
2885 }
2886 
get_startup_sound_sub(dir)2887 char *get_startup_sound_sub(dir)
2888      char *dir;
2889 {
2890   char *buf;
2891   char **p;
2892   static char *startup_sound[] = {"/fkiss.au", "/.fkiss.au", NULL};
2893 
2894   for (p = startup_sound; *p != NULL; p++) {
2895     buf = ks_malloc(strlen(dir) + strlen(*p) + 1);
2896     strcpy(buf, dir);
2897     strcat(buf, *p);
2898     if (is_regular_file(buf))
2899       return buf;
2900     free(buf);
2901   }
2902   return NULL;
2903 }
2904 
get_startup_sound_file()2905 char *get_startup_sound_file()
2906 {
2907   char *p;
2908 
2909   p = get_startup_sound_sub(".");
2910   if (p == NULL) {
2911     if ((p = getenv("HOME")) != NULL)
2912       p = get_startup_sound_sub(p);
2913   }
2914   return p;
2915 }
2916 
play_startup_sound()2917 void play_startup_sound()
2918 {
2919   if (startup_sound_file != NULL)
2920     bg_play(startup_sound_file);
2921 }
2922 
adjust_option()2923 void adjust_option()
2924 {
2925   char *p;
2926 
2927   if (debug_mode)
2928     sound_debug = 2;
2929 #ifndef USE_USLEEP
2930   if (sleep_tick % 1000) {
2931     sleep_tick = sleep_tick - (sleep_tick % 1000) + 1000;
2932     msg("W sleep tick correct %d millisec.\n", sleep_tick);
2933   }
2934 #endif
2935   startup_sound_file = get_startup_sound_file();
2936   /* disable sound, if silent mode is selected */
2937   if (!verbose_mode)
2938     sound_mode = 0;
2939   if (sound_mode) {
2940     p = str_sound_cache_limit;
2941     if (p != NULL) {
2942       sound_cache_limit = strtol(p, &p, 0);
2943       switch (*p) {
2944       case 'm':
2945       case 'M':
2946 	sound_cache_limit *= 1024;
2947 	/* FALL THROUGH */
2948       case 'k':
2949       case 'K':
2950 	sound_cache_limit *= 1024;
2951 	break;
2952       }
2953     }
2954   }
2955 }
2956 
button_func(p)2957 int button_func(p)
2958      XButtonEvent *p;
2959 {
2960   int i;
2961 
2962   switch (p->button) {
2963   case Button1:
2964     i = 1;
2965     break;
2966   case Button2:
2967     i = 2;
2968     break;
2969   case Button3:
2970     i = 3;
2971     break;
2972   default:
2973     i = 0;
2974     break;
2975   }
2976   return button_func_tbl[i];
2977 }
2978 
parse_rc(file)2979 int parse_rc(file)
2980      char *file;
2981 {
2982   char *p;
2983   char *str;
2984   FILE *fp;
2985   int ac;
2986   char **av;
2987   char buf[4096];		/* RC file max line length */
2988   static char charset[] =
2989     "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
2990 
2991   fp = fopen(file, "r");
2992   if (fp == NULL)
2993     return 1;			/* file open error! */
2994   ac = 0;
2995   av = (char **)ks_malloc(sizeof(char *));
2996   while (fgets(buf, sizeof(buf), fp) != NULL) {
2997     cut_crlf(buf);
2998     if ((p = index(buf, '#')) != NULL)
2999       *p = '\0';		/* erase comment */
3000     for (p = buf; *p; ) {
3001       str = parse_string(&p, charset);
3002       *(av+ac) = str;
3003       ac++;
3004       av = (char **)ks_realloc(av, sizeof(char *)*(ac+1));
3005     }
3006   }
3007   *(av+ac) = NULL;
3008   fclose(fp);
3009   while (ac > 0) {
3010     if (parse_option(&ac, &av)) {
3011       if (**av == '-') {
3012 	msg("W unknown option ``%s''.\n", *av);
3013 	kiss_exit(1);
3014       }
3015       break;
3016     }
3017   }
3018   return 0;			/* Success */
3019 }
3020 
read_fkissrc()3021 void read_fkissrc()
3022 {
3023   char *p;
3024   char *buf;
3025 
3026   p = getenv("HOME");
3027   if (p != NULL) {
3028     buf = ks_malloc(strlen(p) + 9 + 1);
3029     sprintf(buf, "%s/.fkissrc", p);
3030     parse_rc(buf);
3031     free(buf);
3032   }
3033 }
3034 
main(argc,argv)3035 int main(argc, argv)
3036      int argc;
3037      char **argv;
3038 {
3039   int i, n;
3040   XEvent ev;
3041   Bool mapped;
3042   char *p;
3043   Bool first_map;
3044   Bool button_pressed;
3045   char msgbuf[1024];
3046 
3047   setup_signal_handler();
3048   oargc = argc--;
3049   oargv = argv++;
3050   msg_init(msgbuf);
3051   init0();
3052   read_fkissrc();
3053   while (argc > 0) {
3054     if (parse_option(&argc, &argv)) {
3055       if (**argv == '-') {
3056 	msg("W unknown option ``%s''.\n", *argv);
3057 	usage();
3058       }
3059       break;
3060     }
3061   }
3062   adjust_option();
3063   if (debug_mode || test_mode || verbose_mode & 2)
3064     print_version();
3065   if (debug_mode)
3066     print_compile_options();
3067   if (sound_mode == 1) {
3068     if (sound_init()) {
3069       msg("W sound device ``%s'' initialize error.\n", sound_device);
3070     }
3071   }
3072   if (background())
3073     msg("W cannot to fork background process!\n");
3074   p = get_client_info();
3075   if (debug_mode || test_mode)
3076     fprintf(stderr, "%s\n", p);
3077   init_screen();
3078   init_object_cell();
3079   arcfilelist = argv;
3080   n = argc;			/* number of archive and cnf arguments */
3081   i = extract_archives(argv, argc);
3082   argv += i;
3083   arcfilecnt += i;
3084   argc -= i;
3085   switch(select_cnf(argc?*argv:NULL)) {
3086   case -2:			/* No cnf */
3087     if (!n)
3088       usage();			/* no archive or cnf given, print usage */
3089     msg("E *.cnf not found!\n");
3090     /* NOT REACHED */
3091   case -1:			/* Cancel */
3092     kiss_exit(0);
3093     /* NOT REACHED */
3094   }
3095 
3096   if (initialize_main1()) {
3097     kiss_exit(1);
3098     /* NOT REACHED */
3099   }
3100   /* This is NOT standard implementation! */
3101   if (fixed < 0) {
3102     if (wkiss_bug_emulation)
3103       max_fix = 99999;
3104     fixed = max_fix > 0 ? max_fix : FIXED_OBJECT;
3105   }
3106   catched_cell2 = catched_cell = -1;
3107   scrdx = scrdy = 0;
3108   button_pressed = mapped = False;
3109   first_map = True;
3110   while (!quit_flag) {
3111     mobjn = -1;
3112     while (!XEventsQueued(dsp, QueuedAfterReading)) {
3113       /* background operation */
3114       image_scroll();
3115       kissevent_timer();
3116       if (XEventsQueued(dsp, QueuedAfterFlush) || !event_detect)
3117 	break;
3118       if (sleep_tick && !button_pressed)
3119 	sleep_time(get_sleep_time());
3120     }
3121     XNextEvent(dsp, &ev);
3122     switch(ev.type) {
3123     case Expose:
3124       if (ev.xexpose.window == imgwin)
3125 	expose_image(ev.xexpose.x, ev.xexpose.y,
3126 		     ev.xexpose.width, ev.xexpose.height);
3127       else if (ev.xexpose.window == comwin)
3128 	expose_comment(&ev.xexpose);
3129       else
3130 	expose_menu(&ev.xexpose);
3131       break;
3132     case MotionNotify:
3133       if (motion_compress)
3134 	while (XCheckTypedEvent(dsp, MotionNotify, &ev))
3135 	  ;
3136       move_check(ev.xmotion.x, ev.xmotion.y);
3137       if (ev.xmotion.window == viewwin) {
3138 	catch_x = ev.xmotion.x;
3139 	catch_y = ev.xmotion.y;
3140       }
3141       break;
3142     case ButtonPress:
3143       switch (button_func(&ev.xbutton)) {
3144       case BUTTON_FUNC_CELL:
3145 	if (!button_pressed) {
3146 	  /* for multi button pressing, check only first press */
3147 	  catch_x = ev.xbutton.x;
3148 	  catch_y = ev.xbutton.y;
3149 	  if (ev.xbutton.window == imgwin) {
3150 	    button_pressed = True;
3151 	    catch_check(ev.xbutton.x, ev.xbutton.y);
3152 	    if (catched_cell2 >= 0 && ev.xbutton.state & ControlMask) {
3153 	      mapping_changed_cell = catched_cell2;
3154 	      alternate_cell_mapping();
3155 	    }
3156 	    kissevent_handler(EVE_PRESS, catched_cell2);
3157 	    if (catched_cell >= 0) {
3158 	      if ((object + (cell+catched_cell)->obj)->pesi <
3159 		  (object + (cell+catched_cell)->obj)->fix)
3160 		kissevent_handler(EVE_FIXCATCH, catched_cell);
3161 	      kissevent_handler(EVE_CATCH, catched_cell);
3162 	      cursor_grip();
3163 	    } else {
3164 	      cursor_scroll();
3165 	      catched_cell = -2;
3166 	    }
3167 	  } else if (ev.xbutton.window == viewwin) {
3168 	    button_pressed = True;
3169 	    cursor_scroll();
3170 	    catched_cell = -2;
3171 	  } else if (ev.xbutton.window == comwin) {
3172 	    button_pressed = True;
3173 	    unmap_comment();	/* Can't happen! */
3174 	  }
3175 	}
3176         press_menu(&ev.xbutton);
3177 	break;
3178       case BUTTON_FUNC_ICONIFY:
3179 	kiss_iconify();
3180 	/* Menu select is not available */
3181 	break;
3182       case BUTTON_FUNC_COMMENT:
3183 	if (ev.xbutton.window == imgwin)
3184 	  map_comment(&ev.xbutton);
3185 	else
3186 	  unmap_comment();
3187 	press_menu(&ev.xbutton);
3188 	break;
3189       }
3190       break;
3191     case ButtonRelease:
3192       switch (button_func(&ev.xbutton)) {
3193       case BUTTON_FUNC_CELL:
3194 	if (button_pressed) {
3195 	  /* for multi button pressing, check only first release */
3196 	  button_pressed = False;
3197 	  cursor_hand();
3198 	  move_check(ev.xbutton.x, ev.xbutton.y);
3199 	  if (mobjn >= 0) {
3200 	    update_pesi(object+mobjn);
3201 	    release_object();
3202 	  }
3203 	  kissevent_handler(EVE_RELEASE, catched_cell2);
3204 	  catched_cell2 = -1;
3205 	  catched_cell = -1;
3206 	}
3207 	press_menu(&ev.xbutton);
3208 	break;
3209       case BUTTON_FUNC_COMMENT:
3210 	unmap_comment();
3211 	press_menu(&ev.xbutton);
3212 	break;
3213       }
3214       break;
3215     case EnterNotify:
3216       if (ev.xcrossing.window == imgwin ||
3217 	  ev.xcrossing.window == comwin) {
3218 	if (catched_cell >= 0)
3219 	  cursor_grip();
3220 	else if (catched_cell == -2)
3221 	  cursor_scroll();
3222 	else
3223 	  cursor_hand();
3224       }
3225       enter_menu(&ev.xcrossing);
3226       break;
3227     case LeaveNotify:
3228       leave_menu(&ev.xcrossing);
3229       break;
3230     case KeyPress:
3231       key_event(&ev.xkey);
3232       break;
3233     case ConfigureNotify:
3234       resize_topwin(ev.xconfigure.width, ev.xconfigure.height);
3235       break;
3236     case MapNotify:
3237       mapped = True;
3238       if (first_map) {
3239 	i = cset;
3240 	cset = -1;
3241 	change_setpal(i, -1);	/* trigger first set event */
3242 	kissevent_handler(EVE_VERSION, 2);
3243 	if (!(kissevent_handler(EVE_BEGIN, 0) & ACTBIT_SOUND))
3244 	  play_startup_sound();
3245 	if (!event_detect)
3246 	  bg_exit();		/* terminate background process */
3247 	first_map = False;
3248       }
3249       break;
3250     case UnmapNotify:
3251       unmap_comment();
3252       break;
3253     case MappingNotify:
3254       XRefreshKeyboardMapping(&ev.xmapping);
3255       break;
3256     case ClientMessage:
3257       debug_printf("ClientMessage message_type %ld, format %d, data %ld\n",
3258 		   ev.xclient.message_type,
3259 		   ev.xclient.format,
3260 		   ev.xclient.data.l[0]);
3261       if (ev.xclient.data.l[0] == wm_delete_window)
3262 	quit_flag = 1;
3263       break;
3264     }
3265     if (mobjn >= 0)
3266       move_object(mobjn, mobjx, mobjy);
3267     image_scroll();
3268     if (test_mode == 1 && mapped && !XEventsQueued(dsp, QueuedAfterFlush)) {
3269       if (!change_setpal(cset+1, -1)) {
3270 	test_mode = 2;		/* test Done. */
3271 	change_menu_func(1);	/* Quit */
3272       }
3273       XSync(dsp, 0);
3274     }
3275   }
3276   kissevent_handler(EVE_END, 0);
3277   kiss_exit(0);
3278   return 0;			/* NOT REACHED */
3279 }
3280 
3281 /* End of file */
3282