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