OSDN Git Service

#37580 sanity_blast()の仕様変更。魔法防御が高いほど致命的な変異を受けやすい問題を直した。 / Change process of sanity_bl...
[hengband/hengband.git] / src / main-x11.c
1 /* File: main-x11.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11
12 #ifdef USE_JP_FONTSTRUCT
13 /*
14  * 日本語(EUC-JAPAN)対応 (-DJP)
15  *    ・漢字フォントの扱いを追加
16  *    ・日本語を含む文字列の表示ルーチン XDrawMultiString() の追加
17  *    ・日本語の表示幅は,フォントの情報によらすASCIIフォントの2倍に固定
18  *
19  * 未対応
20  *      EUC半角の扱い
21  *
22  * 1996/6/7  李 晃伸 (ri@kuis.kyoto-u.ac.jp)
23  */
24 #endif
25 /*
26  * This file helps Angband work with UNIX/X11 computers.
27  *
28  * To use this file, compile with "USE_X11" defined, and link against all
29  * the various "X11" libraries which may be needed.
30  *
31  * See also "main-xaw.c".
32  *
33  * Part of this file provides a user interface package composed of several
34  * pseudo-objects, including "metadpy" (a display), "infowin" (a window),
35  * "infoclr" (a color), and "infofnt" (a font).  Actually, the package was
36  * originally much more interesting, but it was bastardized to keep this
37  * file simple.
38  *
39  * The rest of this file is an implementation of "main-xxx.c" for X11.
40  *
41  * Most of this file is by Ben Harrison (benh@phial.com).
42  */
43
44 /*
45  * The following shell script can be used to launch Angband, assuming that
46  * it was extracted into "~/Angband", and compiled using "USE_X11", on a
47  * Linux machine, with a 1280x1024 screen, using 6 windows (with the given
48  * characteristics), with gamma correction of 1.8 -> (1 / 1.8) * 256 = 142,
49  * and without graphics (add "-g" for graphics).  Just copy this comment
50  * into a file, remove the leading " * " characters (and the head/tail of
51  * this comment), and make the file executable.
52  * 
53  *
54  * #!/bin/csh
55  * 
56  * # Describe attempt
57  * echo "Launching angband..."
58  * sleep 2
59  * 
60  * # Main window
61  * setenv ANGBAND_X11_FONT_0 10x20
62  * setenv ANGBAND_X11_AT_X_0 5
63  * setenv ANGBAND_X11_AT_Y_0 510
64  * 
65  * # Message window
66  * setenv ANGBAND_X11_FONT_1 8x13
67  * setenv ANGBAND_X11_AT_X_1 5
68  * setenv ANGBAND_X11_AT_Y_1 22
69  * setenv ANGBAND_X11_ROWS_1 35
70  * 
71  * # Inventory window
72  * setenv ANGBAND_X11_FONT_2 8x13
73  * setenv ANGBAND_X11_AT_X_2 635
74  * setenv ANGBAND_X11_AT_Y_2 182
75  * setenv ANGBAND_X11_ROWS_3 23
76  * 
77  * # Equipment window
78  * setenv ANGBAND_X11_FONT_3 8x13
79  * setenv ANGBAND_X11_AT_X_3 635
80  * setenv ANGBAND_X11_AT_Y_3 22
81  * setenv ANGBAND_X11_ROWS_3 12
82  * 
83  * # Monster recall window
84  * setenv ANGBAND_X11_FONT_4 6x13
85  * setenv ANGBAND_X11_AT_X_4 817
86  * setenv ANGBAND_X11_AT_Y_4 847
87  * setenv ANGBAND_X11_COLS_4 76
88  * setenv ANGBAND_X11_ROWS_4 11
89  * 
90  * # Object recall window
91  * setenv ANGBAND_X11_FONT_5 6x13
92  * setenv ANGBAND_X11_AT_X_5 817
93  * setenv ANGBAND_X11_AT_Y_5 520
94  * setenv ANGBAND_X11_COLS_5 76
95  * setenv ANGBAND_X11_ROWS_5 24
96  * 
97  * # The build directory
98  * cd ~/Angband
99  *
100  * # Gamma correction
101  * setenv ANGBAND_X11_GAMMA 142
102  * 
103  * # Launch Angband
104  * ./src/angband -mx11 -- -n6 &
105  *
106  */
107
108
109 #include "angband.h"
110
111
112 #ifdef USE_X11
113
114
115 #ifndef __MAKEDEPEND__
116 #include <X11/Xlib.h>
117 #include <X11/Xutil.h>
118 #include <X11/keysym.h>
119 #include <X11/keysymdef.h>
120 #ifdef USE_LOCALE
121 #include <X11/Xlocale.h>
122 #endif
123 #if 0
124 char *XSetIMValues(XIM, ...); /* Hack for XFree86 4.0 */
125 #endif
126 #include <X11/Xatom.h>
127 #endif /* __MAKEDEPEND__ */
128
129 #include <iconv.h>
130 /*
131  * Include some helpful X11 code.
132  */
133 #include "maid-x11.c"
134
135
136 /*
137  * Hack -- avoid some compiler warnings
138  */
139 #define IGNORE_UNUSED_FUNCTIONS
140
141
142 /*
143  * Notes on Colors:
144  *
145  *   1) On a monochrome (or "fake-monochrome") display, all colors
146  *   will be "cast" to "fg," except for the bg color, which is,
147  *   obviously, cast to "bg".  Thus, one can ignore this setting.
148  *
149  *   2) Because of the inner functioning of the color allocation
150  *   routines, colors may be specified as (a) a typical color name,
151  *   (b) a hexidecimal color specification (preceded by a pound sign),
152  *   or (c) by strings such as "fg", "bg", "zg".
153  *
154  *   3) Due to the workings of the init routines, many colors
155  *   may also be dealt with by their actual pixel values.  Note that
156  *   the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
157  *   is not necessarily either black or white.
158  */
159
160
161
162 /**** Generic Types ****/
163
164
165 /*
166  * An X11 pixell specifier
167  */
168 typedef unsigned long Pixell;
169
170 /*
171  * The structures defined below
172  */
173 typedef struct metadpy metadpy;
174 typedef struct infowin infowin;
175 typedef struct infoclr infoclr;
176 typedef struct infofnt infofnt;
177
178
179 /*
180  * A structure summarizing a given Display.
181  *
182  *      - The Display itself
183  *      - The default Screen for the display
184  *      - The virtual root (usually just the root)
185  *      - The default colormap (from a macro)
186  *
187  *      - The "name" of the display
188  *
189  *      - The socket to listen to for events
190  *
191  *      - The width of the display screen (from a macro)
192  *      - The height of the display screen (from a macro)
193  *      - The bit depth of the display screen (from a macro)
194  *
195  *      - The black Pixell (from a macro)
196  *      - The white Pixell (from a macro)
197  *
198  *      - The background Pixell (default: black)
199  *      - The foreground Pixell (default: white)
200  *      - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
201  *
202  *      - Bit Flag: Force all colors to black and white (default: !color)
203  *      - Bit Flag: Allow the use of color (default: depth > 1)
204  *      - Bit Flag: We created 'dpy', and so should nuke it when done.
205  */
206 struct metadpy
207 {
208         Display *dpy;
209         Screen *screen;
210         Window root;
211         Colormap cmap;
212 #ifdef USE_XIM
213         XIM xim;
214 #endif
215
216         char *name;
217
218         int fd;
219
220         uint width;
221         uint height;
222         uint depth;
223
224         Pixell black;
225         Pixell white;
226
227         Pixell bg;
228         Pixell fg;
229         Pixell zg;
230
231         uint mono:1;
232         uint color:1;
233         uint nuke:1;
234 };
235
236
237
238 /*
239  * A Structure summarizing Window Information.
240  *
241  * I assume that a window is at most 30000 pixels on a side.
242  * I assume that the root windw is also at most 30000 square.
243  *
244  *      - The Window
245  *      - The current Input Event Mask
246  *
247  *      - The location of the window
248  *      - The width, height of the window
249  *      - The border width of this window
250  *
251  *      - Byte: 1st Extra byte
252  *
253  *      - Bit Flag: This window is currently Mapped
254  *      - Bit Flag: This window needs to be redrawn
255  *      - Bit Flag: This window has been resized
256  *
257  *      - Bit Flag: We should nuke 'win' when done with it
258  *
259  *      - Bit Flag: 1st extra flag
260  *      - Bit Flag: 2nd extra flag
261  *      - Bit Flag: 3rd extra flag
262  *      - Bit Flag: 4th extra flag
263  */
264 struct infowin
265 {
266         Window win;
267 #ifdef USE_XIM
268         XIC xic;
269         long xic_mask;
270 #endif
271
272         long mask;
273
274         s16b ox, oy;
275
276         s16b x, y;
277         s16b w, h;
278         u16b b;
279
280         byte byte1;
281
282         uint mapped:1;
283         uint redraw:1;
284         uint resize:1;
285
286         uint nuke:1;
287
288         uint flag1:1;
289         uint flag2:1;
290         uint flag3:1;
291         uint flag4:1;
292 };
293
294
295
296
297
298
299 /*
300  * A Structure summarizing Operation+Color Information
301  *
302  *      - The actual GC corresponding to this info
303  *
304  *      - The Foreground Pixell Value
305  *      - The Background Pixell Value
306  *
307  *      - Num (0-15): The operation code (As in Clear, Xor, etc)
308  *      - Bit Flag: The GC is in stipple mode
309  *      - Bit Flag: Destroy 'gc' at Nuke time.
310  */
311 struct infoclr
312 {
313         GC gc;
314
315         Pixell fg;
316         Pixell bg;
317
318         uint code:4;
319         uint stip:1;
320         uint nuke:1;
321 };
322
323
324
325 /*
326  * A Structure to Hold Font Information
327  *
328  *      - The 'XFontStruct*' (yields the 'Font')
329  *
330  *      - The font name
331  *
332  *      - The default character width
333  *      - The default character height
334  *      - The default character ascent
335  *
336  *      - Byte: Pixel offset used during fake mono
337  *
338  *      - Flag: Force monospacing via 'wid'
339  *      - Flag: Nuke info when done
340  */
341 struct infofnt
342 {
343 #ifdef USE_FONTSET
344         XFontSet info;
345 #else
346         XFontStruct *info;
347 #endif
348
349         cptr name;
350
351         s16b wid;
352         s16b twid;
353         s16b hgt;
354         s16b asc;
355
356         byte off;
357
358         uint mono:1;
359         uint nuke:1;
360 };
361
362
363
364
365 /**** Generic Macros ****/
366
367
368
369 /* Set current metadpy (Metadpy) to 'M' */
370 #define Metadpy_set(M) \
371         Metadpy = M
372
373
374 /* Initialize 'M' using Display 'D' */
375 #define Metadpy_init_dpy(D) \
376         Metadpy_init_2(D,cNULL)
377
378 /* Initialize 'M' using a Display named 'N' */
379 #define Metadpy_init_name(N) \
380         Metadpy_init_2((Display*)(NULL),N)
381
382 /* Initialize 'M' using the standard Display */
383 #define Metadpy_init() \
384         Metadpy_init_name("")
385
386
387 /* Init an infowin by giving father as an (info_win*) (or NULL), and data */
388 #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
389         Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
390                           X,Y,W,H,B,FG,BG)
391
392
393 /* Init a top level infowin by pos,size,bord,Colors */
394 #define Infowin_init_top(X,Y,W,H,B,FG,BG) \
395         Infowin_init_data(None,X,Y,W,H,B,FG,BG)
396
397
398 /* Request a new standard window by giving Dad infowin and X,Y,W,H */
399 #define Infowin_init_std(D,X,Y,W,H,B) \
400         Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
401
402
403 /* Set the current Infowin */
404 #define Infowin_set(I) \
405         (Infowin = (I))
406
407
408 /* Set the current Infoclr */
409 #define Infoclr_set(C) \
410         (Infoclr = (C))
411
412
413 #define Infoclr_init_ppo(F,B,O,M) \
414         Infoclr_init_data(F,B,O,M)
415
416 #define Infoclr_init_cco(F,B,O,M) \
417         Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
418
419 #define Infoclr_init_ppn(F,B,O,M) \
420         Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
421
422 #define Infoclr_init_ccn(F,B,O,M) \
423         Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
424
425
426 /* Set the current infofnt */
427 #define Infofnt_set(I) \
428         (Infofnt = (I))
429
430
431 /* Errr: Expose Infowin */
432 #define Infowin_expose() \
433         (!(Infowin->redraw = 1))
434
435 /* Errr: Unxpose Infowin */
436 #define Infowin_unexpose() \
437         (Infowin->redraw = 0)
438
439
440
441 /**** Generic Globals ****/
442
443
444 /*
445  * The "default" values
446  */
447 static metadpy metadpy_default;
448
449
450 /*
451  * The "current" variables
452  */
453 static metadpy *Metadpy = &metadpy_default;
454 static infowin *Infowin = (infowin*)(NULL);
455 #ifdef USE_XIM
456 static infowin *Focuswin = (infowin*)(NULL);
457 #endif
458 static infoclr *Infoclr = (infoclr*)(NULL);
459 #ifdef USE_JP_FONTSTRUCT
460 static infofnt *Infofnt = (infofnt*)(NULL);
461 static infofnt *Infokfnt = (infofnt*)(NULL);
462 #else
463 static infofnt *Infofnt = (infofnt*)(NULL);
464 #endif
465
466
467
468
469 /**** Generic code ****/
470
471
472 #ifdef USE_JP_FONTSTRUCT
473 #define Infokfnt_set(I) \
474         (Infokfnt = (I))
475 #endif
476 /*
477  * Init the current metadpy, with various initialization stuff.
478  *
479  * Inputs:
480  *      dpy:  The Display* to use (if NULL, create it)
481  *      name: The name of the Display (if NULL, the current)
482  *
483  * Notes:
484  *      If 'name' is NULL, but 'dpy' is set, extract name from dpy
485  *      If 'dpy' is NULL, then Create the named Display
486  *      If 'name' is NULL, and so is 'dpy', use current Display
487  *
488  * Return -1 if no Display given, and none can be opened.
489  */
490 static errr Metadpy_init_2(Display *dpy, cptr name)
491 {
492         metadpy *m = Metadpy;
493
494         /*** Open the display if needed ***/
495
496         /* If no Display given, attempt to Create one */
497         if (!dpy)
498         {
499                 /* Attempt to open the display */
500                 dpy = XOpenDisplay(name);
501
502                 /* Failure */
503                 if (!dpy) return (-1);
504
505                 /* We will have to nuke it when done */
506                 m->nuke = 1;
507         }
508
509         /* Since the Display was given, use it */
510         else
511         {
512                 /* We will not have to nuke it when done */
513                 m->nuke = 0;
514         }
515
516
517         /*** Save some information ***/
518
519         /* Save the Display itself */
520         m->dpy = dpy;
521
522         /* Get the Screen and Virtual Root Window */
523         m->screen = DefaultScreenOfDisplay(dpy);
524         m->root = RootWindowOfScreen(m->screen);
525
526         /* Get the default colormap */
527         m->cmap = DefaultColormapOfScreen(m->screen);
528
529         /* Extract the true name of the display */
530         m->name = DisplayString(dpy);
531
532         /* Extract the fd */
533         m->fd = ConnectionNumber(Metadpy->dpy);
534
535         /* Save the Size and Depth of the screen */
536         m->width = WidthOfScreen(m->screen);
537         m->height = HeightOfScreen(m->screen);
538         m->depth = DefaultDepthOfScreen(m->screen);
539
540         /* Save the Standard Colors */
541         m->black = BlackPixelOfScreen(m->screen);
542         m->white = WhitePixelOfScreen(m->screen);
543
544         /*** Make some clever Guesses ***/
545
546         /* Guess at the desired 'fg' and 'bg' Pixell's */
547         m->bg = m->black;
548         m->fg = m->white;
549
550         /* Calculate the Maximum allowed Pixel value.  */
551         m->zg = (1 << m->depth) - 1;
552
553         /* Save various default Flag Settings */
554         m->color = ((m->depth > 1) ? 1 : 0);
555         m->mono = ((m->color) ? 0 : 1);
556
557         /* Return "success" */
558         return (0);
559 }
560
561
562 #ifndef IGNORE_UNUSED_FUNCTIONS
563
564 /*
565  * Nuke the current metadpy
566  */
567 static errr Metadpy_nuke(void)
568 {
569         metadpy *m = Metadpy;
570
571
572         /* If required, Free the Display */
573         if (m->nuke)
574         {
575                 /* Close the Display */
576                 XCloseDisplay(m->dpy);
577
578                 /* Forget the Display */
579                 m->dpy = (Display*)(NULL);
580
581                 /* Do not nuke it again */
582                 m->nuke = 0;
583         }
584
585         /* Return Success */
586         return (0);
587 }
588
589 #endif /* IGNORE_UNUSED_FUNCTIONS */
590
591
592 /*
593  * General Flush/ Sync/ Discard routine
594  */
595 static errr Metadpy_update(int flush, int sync, int discard)
596 {
597         /* Flush if desired */
598         if (flush) XFlush(Metadpy->dpy);
599
600         /* Sync if desired, using 'discard' */
601         if (sync) XSync(Metadpy->dpy, discard);
602
603         /* Success */
604         return (0);
605 }
606
607
608 /*
609  * Make a simple beep
610  */
611 static errr Metadpy_do_beep(void)
612 {
613         /* Make a simple beep */
614         XBell(Metadpy->dpy, 100);
615
616         return (0);
617 }
618
619
620
621 /*
622  * Set the name (in the title bar) of Infowin
623  */
624 static errr Infowin_set_name(cptr name)
625 {
626         Status st;
627         XTextProperty tp;
628         char buf[128];
629         char *bp = buf;
630         strcpy(buf, name);
631         st = XStringListToTextProperty(&bp, 1, &tp);
632         if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
633         return (0);
634 }
635
636
637 #ifndef IGNORE_UNUSED_FUNCTIONS
638
639 /*
640  * Set the icon name of Infowin
641  */
642 static errr Infowin_set_icon_name(cptr name)
643 {
644         Status st;
645         XTextProperty tp;
646         char buf[128];
647         char *bp = buf;
648         strcpy(buf, name);
649         st = XStringListToTextProperty(&bp, 1, &tp);
650         if (st) XSetWMIconName(Metadpy->dpy, Infowin->win, &tp);
651         return (0);
652 }
653
654
655 /*
656  * Nuke Infowin
657  */
658 static errr Infowin_nuke(void)
659 {
660         infowin *iwin = Infowin;
661
662         /* Nuke if requested */
663         if (iwin->nuke)
664         {
665                 /* Destory the old window */
666                 XDestroyWindow(Metadpy->dpy, iwin->win);
667         }
668
669         /* Success */
670         return (0);
671 }
672
673 #endif /* IGNORE_UNUSED_FUNCTIONS */
674
675
676 /*
677  * Prepare a new 'infowin'.
678  */
679 static errr Infowin_prepare(Window xid)
680 {
681         infowin *iwin = Infowin;
682
683         Window tmp_win;
684         XWindowAttributes xwa;
685         int x, y;
686         unsigned int w, h, b, d;
687
688         /* Assign stuff */
689         iwin->win = xid;
690
691         /* Check For Error XXX Extract some ACTUAL data from 'xid' */
692         XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
693
694         /* Apply the above info */
695         iwin->x = x;
696         iwin->y = y;
697         iwin->w = w;
698         iwin->h = h;
699         iwin->b = b;
700
701         /* Check Error XXX Extract some more ACTUAL data */
702         XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
703
704         /* Apply the above info */
705         iwin->mask = xwa.your_event_mask;
706         iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
707
708         /* And assume that we are exposed */
709         iwin->redraw = 1;
710
711         /* Success */
712         return (0);
713 }
714
715
716 #ifndef IGNORE_UNUSED_FUNCTIONS
717
718 /*
719  * Initialize a new 'infowin'.
720  */
721 static errr Infowin_init_real(Window xid)
722 {
723         /* Wipe it clean */
724         (void)WIPE(Infowin, infowin);
725
726         /* Start out non-nukable */
727         Infowin->nuke = 0;
728
729         /* Attempt to Prepare ourself */
730         return (Infowin_prepare(xid));
731 }
732
733 #endif /* IGNORE_UNUSED_FUNCTIONS */
734
735
736 /*
737  * Init an infowin by giving some data.
738  *
739  * Inputs:
740  *      dad: The Window that should own this Window (if any)
741  *      x,y: The position of this Window
742  *      w,h: The size of this Window
743  *      b,d: The border width and pixel depth
744  *
745  * Notes:
746  *      If 'dad == None' assume 'dad == root'
747  */
748 static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
749                               int b, Pixell fg, Pixell bg)
750 {
751         Window xid;
752
753         /* Wipe it clean */
754         (void)WIPE(Infowin, infowin);
755
756
757         /*** Error Check XXX ***/
758
759
760         /*** Create the Window 'xid' from data ***/
761
762         /* What happened here?  XXX XXX XXX */
763
764         /* If no parent given, depend on root */
765         if (dad == None)
766
767 /* #ifdef USE_GRAPHICS
768
769                 xid = XCreateWindow(Metadpy->dpy, Metadpy->root, x, y, w, h, b, 8, InputOutput, CopyFromParent, 0, 0);
770
771         else
772 */
773
774 /* #else */
775
776                 dad = Metadpy->root;
777
778 /* #endif */
779
780         /* Create the Window XXX Error Check */
781         xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
782
783         /* Start out selecting No events */
784         XSelectInput(Metadpy->dpy, xid, 0L);
785
786
787         /*** Prepare the new infowin ***/
788
789         /* Mark it as nukable */
790         Infowin->nuke = 1;
791
792         /* Attempt to Initialize the infowin */
793         return (Infowin_prepare(xid));
794 }
795
796
797
798 /*
799  * Modify the event mask of an Infowin
800  */
801 static errr Infowin_set_mask(long mask)
802 {
803         /* Save the new setting */
804         Infowin->mask = mask;
805
806         /* Execute the Mapping */
807         XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
808
809         /* Success */
810         return (0);
811 }
812
813
814 /*
815  * Request that Infowin be mapped
816  */
817 static errr Infowin_map(void)
818 {
819         /* Execute the Mapping */
820         XMapWindow(Metadpy->dpy, Infowin->win);
821
822         /* Success */
823         return (0);
824 }
825
826
827 #ifndef IGNORE_UNUSED_FUNCTIONS
828
829 /*
830  * Request that Infowin be unmapped
831  */
832 static errr Infowin_unmap(void)
833 {
834         /* Execute the Un-Mapping */
835         XUnmapWindow(Metadpy->dpy, Infowin->win);
836
837         /* Success */
838         return (0);
839 }
840
841 #endif /* IGNORE_UNUSED_FUNCTIONS */
842
843
844 /*
845  * Request that Infowin be raised
846  */
847 static errr Infowin_raise(void)
848 {
849         /* Raise towards visibility */
850         XRaiseWindow(Metadpy->dpy, Infowin->win);
851
852         /* Success */
853         return (0);
854 }
855
856
857 #ifndef IGNORE_UNUSED_FUNCTIONS
858
859 /*
860  * Request that Infowin be lowered
861  */
862 static errr Infowin_lower(void)
863 {
864         /* Lower towards invisibility */
865         XLowerWindow(Metadpy->dpy, Infowin->win);
866
867         /* Success */
868         return (0);
869 }
870
871 #endif /* IGNORE_UNUSED_FUNCTIONS */
872
873
874 /*
875  * Request that Infowin be moved to a new location
876  */
877 static errr Infowin_impell(int x, int y)
878 {
879         /* Execute the request */
880         XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
881
882         /* Success */
883         return (0);
884 }
885
886
887 /*
888  * Resize an infowin
889  */
890 static errr Infowin_resize(int w, int h)
891 {
892         /* Execute the request */
893         XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
894
895         /* Success */
896         return (0);
897 }
898
899
900 #ifndef IGNORE_UNUSED_FUNCTIONS
901
902 /*
903  * Move and Resize an infowin
904  */
905 static errr Infowin_locate(int x, int y, int w, int h)
906 {
907         /* Execute the request */
908         XMoveResizeWindow(Metadpy->dpy, Infowin->win, x, y, w, h);
909
910         /* Success */
911         return (0);
912 }
913
914 #endif /* IGNORE_UNUSED_FUNCTIONS */
915
916
917 /*
918  * Visually clear Infowin
919  */
920 static errr Infowin_wipe(void)
921 {
922         /* Execute the request */
923         XClearWindow(Metadpy->dpy, Infowin->win);
924
925         /* Success */
926         return (0);
927 }
928
929
930 #ifndef IGNORE_UNUSED_FUNCTIONS
931
932 /*
933  * Visually Paint Infowin with the current color
934  */
935 static errr Infowin_fill(void)
936 {
937         /* Execute the request */
938         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc,
939                        0, 0, Infowin->w, Infowin->h);
940
941         /* Success */
942         return (0);
943 }
944
945 #endif /* IGNORE_UNUSED_FUNCTIONS */
946
947
948 /*
949  * A NULL terminated pair list of legal "operation names"
950  *
951  * Pairs of values, first is texttual name, second is the string
952  * holding the decimal value that the operation corresponds to.
953  */
954 static cptr opcode_pairs[] =
955 {
956         "cpy", "3",
957         "xor", "6",
958         "and", "1",
959         "ior", "7",
960         "nor", "8",
961         "inv", "10",
962         "clr", "0",
963         "set", "15",
964
965         "src", "3",
966         "dst", "5",
967
968         "+andReverse", "2",
969         "+andInverted", "4",
970         "+noop", "5",
971         "+equiv", "9",
972         "+orReverse", "11",
973         "+copyInverted", "12",
974         "+orInverted", "13",
975         "+nand", "14",
976         NULL
977 };
978
979
980 /*
981  * Parse a word into an operation "code"
982  *
983  * Inputs:
984  *      str: A string, hopefully representing an Operation
985  *
986  * Output:
987  *      0-15: if 'str' is a valid Operation
988  *      -1:   if 'str' could not be parsed
989  */
990 static int Infoclr_Opcode(cptr str)
991 {
992         register int i;
993
994         /* Scan through all legal operation names */
995         for (i = 0; opcode_pairs[i*2]; ++i)
996         {
997                 /* Is this the right oprname? */
998                 if (streq(opcode_pairs[i*2], str))
999                 {
1000                         /* Convert the second element in the pair into a Code */
1001                         return (atoi(opcode_pairs[i*2+1]));
1002                 }
1003         }
1004
1005         /* The code was not found, return -1 */
1006         return (-1);
1007 }
1008
1009
1010 #ifndef IGNORE_UNUSED_FUNCTIONS
1011
1012 /*
1013  * Request a Pixell by name.  Note: uses 'Metadpy'.
1014  *
1015  * Inputs:
1016  *      name: The name of the color to try to load (see below)
1017  *
1018  * Output:
1019  *      The Pixell value that metched the given name
1020  *      'Metadpy->fg' if the name was unparseable
1021  *
1022  * Valid forms for 'name':
1023  *      'fg', 'bg', 'zg', '<name>' and '#<code>'
1024  */
1025 static Pixell Infoclr_Pixell(cptr name)
1026 {
1027         XColor scrn;
1028
1029         /* Attempt to Parse the name */
1030         if (name && name[0])
1031         {
1032                 /* The 'bg' color is available */
1033                 if (streq(name, "bg")) return (Metadpy->bg);
1034
1035                 /* The 'fg' color is available */
1036                 if (streq(name, "fg")) return (Metadpy->fg);
1037
1038                 /* The 'zg' color is available */
1039                 if (streq(name, "zg")) return (Metadpy->zg);
1040
1041                 /* The 'white' color is available */
1042                 if (streq(name, "white")) return (Metadpy->white);
1043
1044                 /* The 'black' color is available */
1045                 if (streq(name, "black")) return (Metadpy->black);
1046
1047                 /* Attempt to parse 'name' into 'scrn' */
1048                 if (!(XParseColor(Metadpy->dpy, Metadpy->cmap, name, &scrn)))
1049                 {
1050                         plog_fmt("Warning: Couldn't parse color '%s'\n", name);
1051                 }
1052
1053                 /* Attempt to Allocate the Parsed color */
1054                 if (!(XAllocColor(Metadpy->dpy, Metadpy->cmap, &scrn)))
1055                 {
1056                         plog_fmt("Warning: Couldn't allocate color '%s'\n", name);
1057                 }
1058
1059                 /* The Pixel was Allocated correctly */
1060                 else return (scrn.pixel);
1061         }
1062
1063         /* Warn about the Default being Used */
1064         plog_fmt("Warning: Using 'fg' for unknown color '%s'\n", name);
1065
1066         /* Default to the 'Foreground' color */
1067         return (Metadpy->fg);
1068 }
1069
1070
1071 /*
1072  * Initialize a new 'infoclr' with a real GC.
1073  */
1074 static errr Infoclr_init_1(GC gc)
1075 {
1076         infoclr *iclr = Infoclr;
1077
1078         /* Wipe the iclr clean */
1079         (void)WIPE(iclr, infoclr);
1080
1081         /* Assign the GC */
1082         iclr->gc = gc;
1083
1084         /* Success */
1085         return (0);
1086 }
1087
1088
1089 /*
1090  * Nuke an old 'infoclr'.
1091  */
1092 static errr Infoclr_nuke(void)
1093 {
1094         infoclr *iclr = Infoclr;
1095
1096         /* Deal with 'GC' */
1097         if (iclr->nuke)
1098         {
1099                 /* Free the GC */
1100                 XFreeGC(Metadpy->dpy, iclr->gc);
1101         }
1102
1103         /* Forget the current */
1104         Infoclr = (infoclr*)(NULL);
1105
1106         /* Success */
1107         return (0);
1108 }
1109
1110 #endif /* IGNORE_UNUSED_FUNCTIONS */
1111
1112
1113 /*
1114  * Initialize an infoclr with some data
1115  *
1116  * Inputs:
1117  *      fg:   The Pixell for the requested Foreground (see above)
1118  *      bg:   The Pixell for the requested Background (see above)
1119  *      op:   The Opcode for the requested Operation (see above)
1120  *      stip: The stipple mode
1121  */
1122 static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
1123 {
1124         infoclr *iclr = Infoclr;
1125
1126         GC gc;
1127         XGCValues gcv;
1128         unsigned long gc_mask;
1129
1130
1131
1132         /*** Simple error checking of opr and clr ***/
1133
1134         /* Check the 'Pixells' for realism */
1135         if (bg > Metadpy->zg) return (-1);
1136         if (fg > Metadpy->zg) return (-1);
1137
1138         /* Check the data for trueness */
1139         if ((op < 0) || (op > 15)) return (-1);
1140
1141
1142         /*** Create the requested 'GC' ***/
1143
1144         /* Assign the proper GC function */
1145         gcv.function = op;
1146
1147         /* Assign the proper GC background */
1148         gcv.background = bg;
1149
1150         /* Assign the proper GC foreground */
1151         gcv.foreground = fg;
1152
1153         /* Hack -- Handle XOR (xor is code 6) by hacking bg and fg */
1154         if (op == 6) gcv.background = 0;
1155         if (op == 6) gcv.foreground = (bg ^ fg);
1156
1157         /* Assign the proper GC Fill Style */
1158         gcv.fill_style = (stip ? FillStippled : FillSolid);
1159
1160         /* Turn off 'Give exposure events for pixmap copying' */
1161         gcv.graphics_exposures = False;
1162
1163         /* Set up the GC mask */
1164         gc_mask = (GCFunction | GCBackground | GCForeground |
1165                    GCFillStyle | GCGraphicsExposures);
1166
1167         /* Create the GC detailed above */
1168         gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
1169
1170
1171         /*** Initialize ***/
1172
1173         /* Wipe the iclr clean */
1174         (void)WIPE(iclr, infoclr);
1175
1176         /* Assign the GC */
1177         iclr->gc = gc;
1178
1179         /* Nuke it when done */
1180         iclr->nuke = 1;
1181
1182         /* Assign the parms */
1183         iclr->fg = fg;
1184         iclr->bg = bg;
1185         iclr->code = op;
1186         iclr->stip = stip ? 1 : 0;
1187
1188         /* Success */
1189         return (0);
1190 }
1191
1192
1193
1194 /*
1195  * Change the 'fg' for an infoclr
1196  *
1197  * Inputs:
1198  *      fg:   The Pixell for the requested Foreground (see above)
1199  */
1200 static errr Infoclr_change_fg(Pixell fg)
1201 {
1202         infoclr *iclr = Infoclr;
1203
1204
1205         /*** Simple error checking of opr and clr ***/
1206
1207         /* Check the 'Pixells' for realism */
1208         if (fg > Metadpy->zg) return (-1);
1209
1210
1211         /*** Change ***/
1212
1213         /* Change */
1214         XSetForeground(Metadpy->dpy, iclr->gc, fg);
1215
1216         /* Success */
1217         return (0);
1218 }
1219
1220
1221
1222 #ifndef IGNORE_UNUSED_FUNCTIONS
1223
1224 /*
1225  * Nuke an old 'infofnt'.
1226  */
1227 static errr Infofnt_nuke(void)
1228 {
1229         infofnt *ifnt = Infofnt;
1230
1231 #ifdef USE_JP_FONTSTRUCT
1232         infofnt *ikfnt = Infokfnt;
1233 #endif
1234         /* Deal with 'name' */
1235         if (ifnt->name)
1236         {
1237                 /* Free the name */
1238                 string_free(ifnt->name);
1239         }
1240
1241 #ifdef USE_JP_FONTSTRUCT
1242         if (ikfnt->name)
1243         {
1244                 /* Free the name */
1245                 string_free(ikfnt->name);
1246         }
1247 #endif
1248
1249         /* Nuke info if needed */
1250         if (ifnt->nuke)
1251         {
1252                 /* Free the font */
1253 #ifdef USE_FONTSET
1254                 XFreeFontSet(Metadpy->dpy, ifnt->info);
1255 #else
1256                 XFreeFont(Metadpy->dpy, ifnt->info);
1257 #endif
1258         }
1259
1260 #ifdef USE_JP_FONTSTRUCT
1261         if (ikfnt->nuke)
1262         {
1263                 /* Free the font */
1264                 XFreeFont(Metadpy->dpy, ikfnt->info);
1265         }
1266 #endif
1267         /* Success */
1268         return (0);
1269 }
1270
1271 #endif /* IGNORE_UNUSED_FUNCTIONS */
1272
1273
1274 /*
1275  * Prepare a new 'infofnt'
1276  */
1277 #ifdef USE_JP_FONTSTRUCT
1278 static errr Infofnt_prepare(XFontStruct *info, XFontStruct *kinfo)
1279 #else
1280 #ifdef USE_FONTSET
1281 static errr Infofnt_prepare(XFontSet info)
1282 #else
1283 static errr Infofnt_prepare(XFontStruct *info)
1284 #endif
1285 #endif
1286
1287 {
1288         infofnt *ifnt = Infofnt;
1289
1290 #ifdef USE_JP_FONTSTRUCT
1291         infofnt *ikfnt = Infokfnt;
1292 #endif
1293         XCharStruct *cs;
1294 #ifdef USE_FONTSET
1295         XFontStruct **fontinfo;
1296         char **fontname;
1297         int n_fonts;
1298         int ascent, descent, width;
1299 #endif
1300
1301         /* Assign the struct */
1302         ifnt->info = info;
1303
1304 #ifdef USE_FONTSET
1305         n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);
1306
1307         ascent = descent = width = 0;
1308         while(n_fonts-- > 0){
1309                 cs = &((*fontinfo)->max_bounds);
1310                 if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
1311                 if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
1312                 if(((*fontinfo)->max_byte1) > 0){
1313                         /* 多バイト文字の場合は幅半分(端数切り上げ)で評価する */
1314                         if(width < (cs->width+1)/2) width = (cs->width+1)/2;
1315                 }else{
1316                         if(width < cs->width) width = cs->width;
1317                 }
1318                 fontinfo++;
1319                 fontname++;
1320         }
1321         ifnt->asc = ascent;
1322         ifnt->hgt = ascent + descent;
1323         ifnt->wid = width;
1324 #else
1325         /* Jump into the max bouonds thing */
1326         cs = &(info->max_bounds);
1327
1328         /* Extract default sizing info */
1329         ifnt->asc = info->ascent;
1330         ifnt->hgt = info->ascent + info->descent;
1331         ifnt->wid = cs->width;
1332 #endif
1333
1334         if (use_bigtile)
1335                 ifnt->twid = 2 * ifnt->wid;
1336         else
1337                 ifnt->twid = ifnt->wid;
1338
1339 #ifdef USE_JP_FONTSTRUCT
1340     /* Assign the struct */
1341     ikfnt->info = kinfo;
1342  
1343     /* Jump into the max bouonds thing */
1344     cs = &(kinfo->max_bounds);
1345  
1346     /* Extract default sizing info */
1347     ikfnt->asc = kinfo->ascent;
1348     ikfnt->hgt = kinfo->ascent + kinfo->descent;
1349     ikfnt->wid = cs->width;
1350 #endif
1351 #ifndef JP
1352 #ifdef OBSOLETE_SIZING_METHOD
1353         /* Extract default sizing info */
1354         ifnt->asc = cs->ascent;
1355         ifnt->hgt = (cs->ascent + cs->descent);
1356         ifnt->wid = cs->width;
1357 #endif
1358 #endif
1359
1360         /* Success */
1361         return (0);
1362 }
1363
1364
1365 #ifndef IGNORE_UNUSED_FUNCTIONS
1366
1367 /*
1368  * Initialize a new 'infofnt'.
1369  */
1370 #ifdef USE_JP_FONTSTRUCT
1371 static errr Infofnt_init_real(XFontStruct *info, XFontStruct *kinfo)
1372 #else
1373 #ifdef USE_FONTSET
1374 static errr Infofnt_init_real(XFontSet info)
1375 #else
1376 static errr Infofnt_init_real(XFontStruct *info)
1377 #endif
1378 #endif
1379
1380 {
1381         /* Wipe the thing */
1382         (void)WIPE(Infofnt, infofnt);
1383
1384 #ifdef USE_JP_FONTSTRUCT
1385         WIPE(Infokfnt, infofnt);
1386 #endif
1387         /* No nuking */
1388         Infofnt->nuke = 0;
1389
1390 #ifdef USE_JP_FONTSTRUCT
1391         Infokfnt->nuke = 0;
1392 #endif
1393         /* Attempt to prepare it */
1394 #ifdef USE_JP_FONTSTRUCT
1395         return (Infofnt_prepare (info, kinfo));
1396 #else
1397         return (Infofnt_prepare(info));
1398 #endif
1399
1400 }
1401
1402 #endif /* IGNORE_UNUSED_FUNCTIONS */
1403
1404
1405 /*
1406  * Init an infofnt by its Name
1407  *
1408  * Inputs:
1409  *      name: The name of the requested Font
1410  */
1411 #ifdef USE_JP_FONTSTRUCT
1412 static void Infofnt_init_data(cptr name, cptr kname)
1413 #else
1414 static void Infofnt_init_data(cptr name)
1415 #endif
1416
1417 {
1418 #ifdef USE_FONTSET
1419         XFontSet info;
1420         char **missing_list;
1421         int missing_count;
1422         char *default_font;
1423 #else
1424         XFontStruct *info;
1425 #endif
1426
1427
1428 #ifdef USE_JP_FONTSTRUCT
1429         XFontStruct *kinfo;
1430 #endif
1431         /*** Load the info Fresh, using the name ***/
1432
1433         /* If the name is not given, report an error */
1434         if (!name || !*name) quit("Missing font!");
1435
1436 #ifdef USE_JP_FONTSTRUCT
1437         if (!kname || !*kname) quit("Missing kanji font!");
1438 #endif
1439         /* Attempt to load the font */
1440 #ifdef USE_FONTSET
1441         info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
1442         if(missing_count > 0){
1443                 printf("missing font(s): \n");
1444                 while(missing_count-- > 0){
1445                         printf("\t%s\n", missing_list[missing_count]);
1446                 }
1447                 XFreeStringList(missing_list);
1448         }
1449 #else
1450         info = XLoadQueryFont(Metadpy->dpy, name);
1451 #ifdef USE_JP_FONTSTRUCT
1452         kinfo = XLoadQueryFont(Metadpy->dpy, kname);
1453 #endif
1454 #endif
1455
1456
1457         /* The load failed, try to recover */
1458         if (!info) quit_fmt("Failed to find font:\"%s\"", name);
1459 #ifdef USE_JP_FONTSTRUCT
1460         if (!kinfo) quit_fmt("Failed to find font:\"%s\"", kname);
1461 #endif
1462
1463
1464
1465         /*** Init the font ***/
1466
1467         /* Wipe the thing */
1468         (void)WIPE(Infofnt, infofnt);
1469
1470 #ifdef USE_JP_FONTSTRUCT
1471         WIPE(Infokfnt, infofnt);
1472 #endif
1473         /* Attempt to prepare it */
1474 #ifdef USE_JP_FONTSTRUCT
1475         if (Infofnt_prepare(info, kinfo))
1476 #else
1477         if (Infofnt_prepare(info))
1478 #endif
1479
1480         {
1481                 /* Free the font */
1482 #ifdef USE_FONTSET
1483                 XFreeFontSet(Metadpy->dpy, info);
1484 #else
1485                 XFreeFont(Metadpy->dpy, info);
1486 #ifdef USE_JP_FONTSTRUCT
1487                 XFreeFont(Metadpy->dpy, kinfo);
1488 #endif
1489 #endif
1490                 /* Fail */
1491                 quit_fmt("Failed to prepare font:\"%s\"", name);
1492         }
1493
1494         /* Save a copy of the font name */
1495         Infofnt->name = string_make(name);
1496 #ifdef USE_JP_FONTSTRUCT
1497         Infokfnt->name = string_make(kname);
1498 #endif
1499
1500         /* Mark it as nukable */
1501         Infofnt->nuke = 1;
1502 #ifdef USE_JP_FONTSTRUCT
1503         Infokfnt->nuke = 1;
1504 #endif
1505 }
1506
1507
1508 #ifdef USE_JP_FONTSTRUCT
1509 /*
1510  * EUC日本語コードを含む文字列を表示する (Xlib)
1511  */
1512 static void
1513 XDrawMultiString(display,d,gc, x, y, string, len, afont, 
1514       afont_width, afont_height, afont_ascent, kfont, kfont_width)
1515     Display *display;
1516     Drawable d;
1517     GC gc;
1518     int       x, y;
1519     char      *string;
1520     int len;
1521     XFontStruct *afont;
1522     int afont_width, afont_height, afont_ascent;
1523     XFontStruct *kfont;
1524     int kfont_width;
1525 {
1526     XChar2b       kanji[500];
1527     char *p;
1528     unsigned char *str;
1529     unsigned char *endp;
1530     int slen;
1531     str = string;
1532     endp = string + len;
1533
1534     while ( str < endp && *str ) {
1535
1536 #ifdef TOFU      
1537       if ( (*str) == 0x7f ) {
1538           
1539           /* 0x7Fは■で決め打ち */
1540           
1541           /* 連続する0x7Fの長さを検出 */
1542           slen = 0;
1543           while ( str < endp && (*str) == 0x7f ) {
1544               slen++; 
1545               str++;
1546           }
1547           
1548           /* 描画 */
1549           XFillRectangle( display, d, gc, x, y-afont_ascent, 
1550                           slen * afont_width, afont_height);
1551  
1552           /* ポインタを進める */
1553           x += afont_width * slen;
1554       } 
1555       else  
1556 #endif
1557       if ( iskanji(*str) ) {
1558           
1559           /* UJISの始まり */
1560           
1561           /* 連続するUJIS文字の長さを検出 */
1562           slen = 0;
1563           while ( str < endp && *str && iskanji(*str) ) {
1564               kanji[slen].byte1 = *str++ & 0x7f;
1565               kanji[slen++].byte2 = *str++ & 0x7f;
1566           }
1567           
1568           /* 描画 */
1569           XSetFont( display, gc, kfont->fid );
1570           XDrawImageString16( display, d, gc, x, y, kanji, slen );
1571
1572  
1573           /* ポインタを進める */
1574           x += kfont_width * slen;
1575           
1576       } else {
1577           
1578           /* 非漢字(=ASCIIと仮定)の始まり */
1579           
1580           /* 連続するASCII文字を検出 */
1581           p = str;
1582           slen = 0;
1583           while ( str < endp && *str && !iskanji(*str) ) {
1584 #ifdef TOFU
1585               if (*str == 0x7f)break;
1586 #endif
1587               str++;
1588               slen++;
1589           }
1590           
1591           /* 描画 */
1592           XSetFont( display, gc, afont->fid );
1593           XDrawImageString( display, d, gc, x, y, p, slen );
1594           
1595           /* ポインタを進める */
1596           x += afont_width * slen;
1597       }
1598     }
1599 }
1600 #endif
1601
1602 /*
1603  * Standard Text
1604  */
1605 static errr Infofnt_text_std(int x, int y, cptr str, int len)
1606 {
1607         int i;
1608
1609
1610         /*** Do a brief info analysis ***/
1611
1612         /* Do nothing if the string is null */
1613         if (!str || !*str) return (-1);
1614
1615         /* Get the length of the string */
1616         if (len < 0) len = strlen(str);
1617
1618         /*** Decide where to place the string, vertically ***/
1619
1620         /* Ignore Vertical Justifications */
1621         y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
1622
1623
1624         /*** Decide where to place the string, horizontally ***/
1625
1626         /* Line up with x at left edge of column 'x' */
1627         x = (x * Infofnt->wid) + Infowin->ox;
1628
1629
1630         /*** Actually draw 'str' onto the infowin ***/
1631
1632 #ifndef USE_FONTSET
1633         /* Be sure the correct font is ready */
1634         XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1635 #endif
1636
1637         /*** Handle the fake mono we can enforce on fonts ***/
1638
1639         /* Monotize the font */
1640         if (Infofnt->mono)
1641         {
1642 #ifdef USE_JP_FONTSTRUCT
1643                 /* Be sure the correct font is ready */
1644                 XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1645 #endif
1646                 /* Do each character */
1647                 for (i = 0; i < len; ++i)
1648                 {
1649                         /* Note that the Infoclr is set up to contain the Infofnt */
1650                         XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1651                                          x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
1652                 }
1653         }
1654
1655         /* Assume monoospaced font */
1656         else
1657         {
1658                 /* Note that the Infoclr is set up to contain the Infofnt */
1659 #ifdef USE_JP_FONTSTRUCT
1660                 /* 漢字フォントの表示幅は ASCIIフォントの2倍に固定 */
1661                 XDrawMultiString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1662                                  x, y, str, len,
1663                                  Infofnt->info, Infofnt->wid, Infofnt->hgt,
1664                                  Infofnt->asc, 
1665                                  Infokfnt->info, Infofnt->wid * 2);
1666 #else
1667 #ifdef USE_FONTSET
1668
1669                 iconv_t cd = iconv_open("UTF-8", "EUC-JP");
1670                 size_t inlen = len;
1671                 size_t outlen = len * 2;
1672                 char *kanji = malloc(outlen);
1673                 char *sp = str; char *kp = kanji;
1674                 size_t n = iconv(cd, &sp, &inlen, &kp, &outlen);
1675                 iconv_close(cd);
1676
1677                 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
1678                                 Infoclr->gc, x, y, kanji, kp-kanji);
1679                 free(kanji);
1680 #else
1681                 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1682                                  x, y, str, len);
1683 #endif
1684 #endif
1685
1686         }
1687
1688
1689         /* Success */
1690         return (0);
1691 }
1692
1693
1694 /*
1695  * Painting where text would be
1696  */
1697 static errr Infofnt_text_non(int x, int y, cptr str, int len)
1698 {
1699         int w, h;
1700
1701
1702         /*** Find the width ***/
1703
1704         /* Negative length is a flag to count the characters in str */
1705         if (len < 0) len = strlen(str);
1706
1707         /* The total width will be 'len' chars * standard width */
1708         w = len * Infofnt->wid;
1709
1710
1711         /*** Find the X dimensions ***/
1712
1713         /* Line up with x at left edge of column 'x' */
1714         x = x * Infofnt->wid + Infowin->ox;
1715
1716
1717         /*** Find other dimensions ***/
1718
1719         /* Simply do 'Infofnt->hgt' (a single row) high */
1720         h = Infofnt->hgt;
1721
1722         /* Simply do "at top" in row 'y' */
1723         y = y * h + Infowin->oy;
1724
1725
1726         /*** Actually 'paint' the area ***/
1727
1728         /* Just do a Fill Rectangle */
1729         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
1730
1731         /* Success */
1732         return (0);
1733 }
1734
1735
1736
1737 /*************************************************************************/
1738
1739
1740 /*
1741  * Angband specific code follows... (ANGBAND)
1742  */
1743
1744
1745 /*
1746  * Hack -- cursor color
1747  */
1748 static infoclr *xor;
1749
1750 /*
1751  * Actual color table
1752  */
1753 static infoclr *clr[256];
1754
1755 /*
1756  * Color info (unused, red, green, blue).
1757  */
1758 static byte color_table[256][4];
1759
1760 /*
1761  * Forward declare
1762  */
1763 typedef struct term_data term_data;
1764
1765 /*
1766  * A structure for each "term"
1767  */
1768 struct term_data
1769 {
1770         term t;
1771
1772         infofnt *fnt;
1773 #ifdef USE_JP_FONTSTRUCT
1774         infofnt *kfnt;
1775 #endif
1776
1777
1778         infowin *win;
1779
1780 #ifdef USE_GRAPHICS
1781
1782         XImage *tiles;
1783
1784         /* Tempory storage for overlaying tiles. */
1785         XImage *TmpImage;
1786
1787 #endif
1788
1789 };
1790
1791
1792 /*
1793  * The number of term data structures
1794  */
1795 #define MAX_TERM_DATA 8
1796
1797 /*
1798  * The array of term data structures
1799  */
1800 static term_data data[MAX_TERM_DATA];
1801
1802
1803 /* Use short names for the most commonly used elements of various structures. */
1804 #define DPY (Metadpy->dpy)
1805 #define WIN (Infowin->win)
1806
1807
1808 /* Describe a set of co-ordinates. */
1809 typedef struct co_ord co_ord;
1810 struct co_ord
1811 {
1812         int x;
1813         int y;
1814 };
1815
1816
1817 /*
1818  * A special structure to store information about the text currently
1819  * selected.
1820  */
1821 typedef struct x11_selection_type x11_selection_type;
1822 struct x11_selection_type
1823 {
1824         bool select; /* The selection is currently in use. */
1825         bool drawn; /* The selection is currently displayed. */
1826         term *t; /* The window where the selection is found. */
1827         co_ord init; /* The starting co-ordinates. */
1828         co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1829         co_ord old; /* The previous end co-ordinates. */
1830         Time time; /* The time at which the selection was finalised. */
1831 };
1832
1833 static x11_selection_type s_ptr[1];
1834
1835
1836 /*
1837  * Process a keypress event
1838  *
1839  * Also appears in "main-xaw.c".
1840  */
1841 static void react_keypress(XKeyEvent *xev)
1842 {
1843         int i, n, mc, ms, mo, mx;
1844
1845         uint ks1;
1846
1847         XKeyEvent *ev = (XKeyEvent*)(xev);
1848
1849         KeySym ks;
1850
1851         char buf[128];
1852         char msg[128];
1853
1854 #ifdef USE_XIM
1855         int valid_keysym = TRUE;
1856 #endif
1857
1858         /* Check for "normal" keypresses */
1859 #ifdef USE_XIM
1860         if(Focuswin && Focuswin->xic){
1861                 Status status;
1862                 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1863                 if(status == XBufferOverflow){
1864                         printf("Input is too long, and dropped\n");
1865                         return;
1866                 }
1867                 if(status != XLookupKeySym && status != XLookupBoth){
1868                         valid_keysym = FALSE;
1869                 }
1870         }else{
1871                 n = XLookupString(ev, buf, 125, &ks, NULL);
1872         }
1873 #else
1874         n = XLookupString(ev, buf, 125, &ks, NULL);
1875 #endif
1876
1877         /* Terminate */
1878         buf[n] = '\0';
1879
1880 #ifdef USE_XIM
1881         if(!valid_keysym){
1882                 /* Enqueue the normal key(s) */
1883                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1884
1885                 /* All done */
1886                 return;
1887         }
1888 #endif
1889
1890         /* Hack -- Ignore "modifier keys" */
1891         if (IsModifierKey(ks)) return;
1892
1893
1894         /* Hack -- convert into an unsigned int */
1895         ks1 = (uint)(ks);
1896
1897         /* Extract four "modifier flags" */
1898         mc = (ev->state & ControlMask) ? TRUE : FALSE;
1899         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1900         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1901         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1902
1903
1904         /* Normal keys with no modifiers */
1905         if (n && !mo && !mx && !IsSpecialKey(ks))
1906         {
1907                 /* Enqueue the normal key(s) */
1908                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1909
1910                 /* All done */
1911                 return;
1912         }
1913
1914
1915         /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1916         switch (ks1)
1917         {
1918                 case XK_Escape:
1919                 {
1920                         Term_keypress(ESCAPE);
1921                         return;
1922                 }
1923
1924                 case XK_Return:
1925                 {
1926                         Term_keypress('\r');
1927                         return;
1928                 }
1929
1930                 case XK_Tab:
1931                 {
1932                         Term_keypress('\t');
1933                         return;
1934                 }
1935
1936                 case XK_Delete:
1937                 {
1938                         Term_keypress(0x7f);
1939                         return;
1940                 }
1941                 case XK_BackSpace:
1942                 {
1943                         Term_keypress('\010');
1944                         return;
1945                 }
1946         }
1947
1948
1949         /* Hack -- Use the KeySym */
1950         if (ks)
1951         {
1952                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1953                         mc ? "N" : "", ms ? "S" : "",
1954                         mo ? "O" : "", mx ? "M" : "",
1955                         (unsigned long)(ks), 13);
1956         }
1957
1958         /* Hack -- Use the Keycode */
1959         else
1960         {
1961                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1962                         mc ? "N" : "", ms ? "S" : "",
1963                         mo ? "O" : "", mx ? "M" : "",
1964                         ev->keycode, 13);
1965         }
1966
1967         /* Enqueue the "macro trigger" string */
1968         for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1969
1970
1971         /* Hack -- auto-define macros as needed */
1972         if (n && (macro_find_exact(msg) < 0))
1973         {
1974                 /* Create a macro */
1975                 macro_add(msg, buf);
1976         }
1977 }
1978
1979
1980 /*
1981  * Find the square a particular pixel is part of.
1982  */
1983 static void pixel_to_square(int * const x, int * const y,
1984         const int ox, const int oy)
1985 {
1986         (*x) = (ox - Infowin->ox) / Infofnt->wid;
1987         (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1988 }
1989
1990 /*
1991  * Find the pixel at the top-left corner of a square.
1992  */
1993 static void square_to_pixel(int * const x, int * const y,
1994         const int ox, const int oy)
1995 {
1996         (*x) = ox * Infofnt->wid + Infowin->ox;
1997         (*y) = oy * Infofnt->hgt + Infowin->oy;
1998 }
1999
2000 /*
2001  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
2002  */
2003 static void sort_co_ord(co_ord *min, co_ord *max,
2004         const co_ord *b, const co_ord *a)
2005 {
2006         min->x = MIN(a->x, b->x);
2007         min->y = MIN(a->y, b->y);
2008         max->x = MAX(a->x, b->x);
2009         max->y = MAX(a->y, b->y);
2010 }
2011
2012 /*
2013  * Remove the selection by redrawing it.
2014  */
2015 static void mark_selection_clear(int x1, int y1, int x2, int y2)
2016 {
2017         Term_redraw_section(x1,y1,x2,y2);
2018 }
2019
2020 /*
2021  * Select an area by drawing a grey box around it.
2022  * NB. These two functions can cause flicker as the selection is modified,
2023  * as the game redraws the entire marked section.
2024  */
2025 static void mark_selection_mark(int x1, int y1, int x2, int y2)
2026 {
2027         square_to_pixel(&x1, &y1, x1, y1);
2028         square_to_pixel(&x2, &y2, x2, y2);
2029         XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
2030                 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
2031 }
2032
2033 /*
2034  * Mark a selection by drawing boxes around it (for now).
2035  */
2036 static void mark_selection(void)
2037 {
2038         co_ord min, max;
2039         term *old = Term;
2040         bool draw = s_ptr->select;
2041         bool clear = s_ptr->drawn;
2042
2043         /* Open the correct term if necessary. */
2044         if (s_ptr->t != old) Term_activate(s_ptr->t);
2045
2046         if (clear)
2047         {
2048                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
2049                 mark_selection_clear(min.x, min.y, max.x, max.y);
2050         }
2051         if (draw)
2052         {
2053                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2054                 mark_selection_mark(min.x, min.y, max.x, max.y);
2055         }
2056
2057         /* Finish on the current term. */
2058         if (s_ptr->t != old) Term_activate(old);
2059
2060         s_ptr->old.x = s_ptr->cur.x;
2061         s_ptr->old.y = s_ptr->cur.y;
2062         s_ptr->drawn = s_ptr->select;
2063 }
2064
2065 /*
2066  * Forget a selection for one reason or another.
2067  */
2068 static void copy_x11_release(void)
2069 {
2070         /* Deselect the current selection. */
2071         s_ptr->select = FALSE;
2072
2073         /* Remove its graphical represesntation. */
2074         mark_selection();
2075 }
2076
2077 /*
2078  * Start to select some text on the screen.
2079  */
2080 static void copy_x11_start(int x, int y)
2081 {
2082         if (s_ptr->select) copy_x11_release();
2083
2084         /* Remember where the selection started. */
2085         s_ptr->t = Term;
2086         s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
2087         s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
2088 }
2089
2090 /*
2091  * Respond to movement of the mouse when selecting text.
2092  */
2093 static void copy_x11_cont(int x, int y, unsigned int buttons)
2094 {
2095         /* Use the nearest square within bounds if the mouse is outside. */
2096         x = MIN(MAX(x, 0), Term->wid-1);
2097         y = MIN(MAX(y, 0), Term->hgt-1);
2098
2099         /* The left mouse button isn't pressed. */
2100         if (~buttons & Button1Mask) return;
2101
2102         /* Not a selection in this window. */
2103         if (s_ptr->t != Term) return;
2104
2105         /* Not enough movement. */
2106         if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
2107
2108         /* Something is being selected. */
2109         s_ptr->select = TRUE;
2110
2111         /* Track the selection. */
2112         s_ptr->cur.x = x;
2113         s_ptr->cur.y = y;
2114
2115         /* Hack - display it inefficiently. */
2116         mark_selection();
2117 }
2118
2119 /*
2120  * Respond to release of the left mouse button by putting the selected text in
2121  * the primary buffer.
2122  */
2123 static void copy_x11_end(const Time time)
2124 {
2125         /* No selection. */
2126         if (!s_ptr->select) return;
2127
2128         /* Not a selection in this window. */
2129         if (s_ptr->t != Term) return;
2130
2131         /* Remember when the selection was finalised. */
2132         s_ptr->time = time;
2133
2134         /* Acquire the primary selection. */
2135         XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
2136         if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
2137         {
2138                 /* Failed to acquire the selection, so forget it. */
2139                 /* bell("Failed to acquire primary buffer."); */
2140                 s_ptr->select = FALSE;
2141                 mark_selection();
2142         }
2143 }
2144
2145
2146 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
2147
2148 /*
2149  * Set the required variable atoms at start-up to avoid errors later.
2150  */
2151 static void set_atoms(void)
2152 {
2153         xa_targets = XInternAtom(DPY, "TARGETS", False);
2154         xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
2155         xa_text = XInternAtom(DPY, "TEXT", False);
2156         xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
2157 }
2158
2159
2160 static Atom request_target = 0;
2161
2162 /*
2163  * Send a message to request that the PRIMARY buffer be sent here.
2164  */
2165 static void paste_x11_request(Atom target, const Time time)
2166 {
2167         /*
2168          * It's from some sample programs on the web.
2169          * What does it mean? -- XXX
2170          */
2171         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2172
2173         /* Check the owner. */
2174         if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
2175         {
2176                 /* No selection. */
2177                 /* bell("No selection found."); */
2178                 return;
2179         }
2180
2181         request_target = target;
2182     
2183         /* Request the event */
2184         XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
2185 }
2186
2187
2188 /*
2189  * Add the contents of the PRIMARY buffer to the input queue.
2190  *
2191  * Hack - This doesn't use the "time" of the event, and so accepts anything a
2192  * client tries to send it.
2193  */
2194 static void paste_x11_accept(const XSelectionEvent *ptr)
2195 {
2196         unsigned long left;
2197         const long offset = 0;
2198         const long length = 32000;
2199         XTextProperty xtextproperty;
2200         errr err = 0;
2201
2202         /*
2203          * It's from some sample programs on the web.
2204          * What does it mean? -- XXX
2205          */
2206         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2207
2208
2209         /* Failure. */
2210         if (ptr->property == None)
2211         {
2212                 if (request_target == xa_compound_text)
2213                 {
2214                         /* Re-request as STRING */
2215                         paste_x11_request(XA_STRING, ptr->time);
2216                 }
2217                 else
2218                 {
2219                         request_target = 0;
2220                         plog("Paste failure (remote client could not send).");
2221                 }
2222                 return;
2223         }
2224
2225         if (ptr->selection != XA_PRIMARY)
2226         {
2227                 plog("Paste failure (remote client did not send primary selection).");
2228                 return;
2229         }
2230
2231         if (ptr->target != request_target)
2232         {
2233                 plog("Paste failure (selection in unknown format).");
2234                 return;
2235         }
2236
2237         /* Get text */
2238         if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
2239                                length, TRUE, request_target,
2240                                &xtextproperty.encoding,
2241                                &xtextproperty.format,
2242                                &xtextproperty.nitems,
2243                                &left,
2244                                &xtextproperty.value)
2245             != Success)
2246         {
2247                 /* Failure */
2248                 return;
2249         }
2250
2251         if (request_target == xa_compound_text)
2252         {
2253                 char **list;
2254                 int count;
2255                 
2256                 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
2257
2258                 if (list)
2259                 {
2260                         int i;
2261
2262                         for (i = 0; i < count; i++)
2263                         {
2264                                 /* Paste the text. */
2265                                 err = type_string(list[i], 0);
2266
2267                                 if (err) break;
2268                         }
2269
2270                         /* Free the string */
2271                         XFreeStringList(list);
2272                 }
2273         }
2274         else /* if (request_target == XA_STRING) */
2275         {
2276                 /* Paste the text. */
2277                 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
2278         }
2279
2280         /* Free the data pasted. */
2281         XFree(xtextproperty.value); 
2282
2283         /* No room. */
2284         if (err)
2285         {
2286                 plog("Paste failure (too much text selected).");
2287         }
2288 }
2289
2290
2291 /*
2292  * Add a character to a string in preparation for sending it to another
2293  * client as a STRING.
2294  * This doesn't change anything, as clients tend not to have difficulty in
2295  * receiving this format (although the standard specifies a restricted set).
2296  * Strings do not have a colour.
2297  */
2298 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
2299 {
2300         char buf[1024];
2301         char *list[1000];
2302         co_ord max, min;
2303         int x,y,l,n;
2304         byte a;
2305         char c;
2306
2307         /* Too old, or incorrect call. */
2308         if (rq->time < s_ptr->time) return FALSE;
2309
2310         /* Work out which way around to paste. */
2311         sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2312
2313         /* Paranoia. */
2314         if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
2315         {
2316                 /* bell("Someone stole my selection!"); */
2317                 return FALSE;
2318         }
2319
2320         /* Delete the old value of the property. */
2321         XDeleteProperty(DPY, rq->requestor, rq->property);
2322
2323         for (n = 0, y = 0; y < Term->hgt; y++)
2324         {
2325 #ifdef JP
2326                 int kanji = 0;
2327 #endif
2328                 if (y < min.y) continue;
2329                 if (y > max.y) break;
2330
2331                 for (l = 0, x = 0; x < Term->wid; x++)
2332                 {
2333 #ifdef JP
2334                         if (x > max.x) break;
2335
2336                         /* Find the character. */
2337                         Term_what(x, y, &a, &c);
2338
2339                         if (1 == kanji) kanji = 2;
2340                         else if (iskanji(c)) kanji = 1;
2341                         else kanji = 0;
2342
2343                         if (x < min.x) continue;
2344
2345                         /*
2346                          * A single kanji character was divided in two...
2347                          * Delete the garbage.
2348                          */
2349                         if ((2 == kanji && x == min.x) ||
2350                             (1 == kanji && x == max.x))
2351                                 c = ' ';
2352 #else
2353                         if (x > max.x) break;
2354                         if (x < min.x) continue;
2355
2356                         /* Find the character. */
2357                         Term_what(x, y, &a, &c);
2358 #endif
2359
2360                         /* Add it. */
2361                         buf[l] = c;
2362                         l++;
2363                 }
2364
2365                 /* Ignore trailing spaces */
2366                 while (buf[l-1] == ' ') l--;
2367
2368                 /* Terminate all line unless it's single line. */
2369                 if (min.y != max.y)
2370                 {
2371                         buf[l] = '\n';
2372                         l++;
2373                 }
2374
2375                 /* End of string */
2376                 buf[l] = '\0';
2377
2378                 list[n++] = (char *)string_make(buf);
2379         }
2380
2381         /* End of the list */
2382         list[n] = NULL;
2383
2384
2385         if (rq->target == XA_STRING)
2386         {
2387                 for (n = 0; list[n]; n++)
2388                 {
2389                         /* Send the (non-empty) string. */
2390                         XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
2391                                         PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
2392                 }
2393         }
2394
2395         else if (rq->target == xa_text || 
2396                  rq->target == xa_compound_text)
2397         {
2398                 XTextProperty text_prop;
2399                 XICCEncodingStyle style;
2400
2401                 if (rq->target == xa_text)
2402                         style = XStdICCTextStyle;
2403                 else /* if (rq->target == xa_compound_text) */
2404                         style = XCompoundTextStyle;
2405
2406                 if (Success ==
2407                     XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
2408                 {
2409                         /* Send the compound text */
2410                         XChangeProperty(DPY,
2411                                         rq->requestor,
2412                                         rq->property,
2413                                         text_prop.encoding,
2414                                         text_prop.format,
2415                                         PropModeAppend,
2416                                         text_prop.value,
2417                                         text_prop.nitems);
2418                                 
2419                         /* Free the data. */
2420                         XFree(text_prop.value);
2421                 }
2422         }
2423
2424         /* Free the list of strings */
2425         for (n = 0; list[n]; n++)
2426         {
2427                 string_free(list[n]);
2428         }
2429
2430         return TRUE;
2431 }
2432
2433 /*
2434  * Send some text requested by another X client.
2435  */
2436 static void paste_x11_send(XSelectionRequestEvent *rq)
2437 {
2438         XEvent event;
2439         XSelectionEvent *ptr = &(event.xselection);
2440
2441         /* Set the event parameters. */
2442         ptr->type = SelectionNotify;
2443         ptr->property = rq->property;
2444         ptr->display = rq->display;
2445         ptr->requestor = rq->requestor;
2446         ptr->selection = rq->selection;
2447         ptr->target = rq->target;
2448         ptr->time = rq->time;
2449
2450         /* Paste the appropriate information for each target type.
2451          * Note that this currently rejects MULTIPLE targets.
2452          */
2453
2454         if (rq->target == XA_STRING ||
2455             rq->target == xa_text ||
2456             rq->target == xa_compound_text)
2457         {
2458                 if (!paste_x11_send_text(rq))
2459                         ptr->property = None;
2460         }
2461         else if (rq->target == xa_targets)
2462         {
2463                 Atom target_list[4];
2464                 target_list[0] = XA_STRING;
2465                 target_list[1] = xa_text;
2466                 target_list[2] = xa_compound_text;
2467                 target_list[3] = xa_targets;
2468                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2469                         (8 * sizeof(target_list[0])), PropModeReplace,
2470                         (unsigned char *)target_list,
2471                         (sizeof(target_list) / sizeof(target_list[0])));
2472         }
2473         else if (rq->target == xa_timestamp)
2474         {
2475                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2476                         (8 * sizeof(Time)), PropModeReplace,
2477                         (unsigned char *)s_ptr->time, 1);
2478         }
2479         else
2480         {
2481                 ptr->property = None;
2482         }
2483
2484         /* Send whatever event we're left with. */
2485         XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
2486 }
2487
2488
2489 /*
2490  * Handle various events conditional on presses of a mouse button.
2491  */
2492 static void handle_button(Time time, int x, int y, int button,
2493         bool press)
2494 {
2495         /* The co-ordinates are only used in Angband format. */
2496         pixel_to_square(&x, &y, x, y);
2497
2498         if (press && button == 1) copy_x11_start(x, y);
2499         if (!press && button == 1) copy_x11_end(time);
2500         if (!press && button == 2) paste_x11_request(xa_compound_text, time);
2501 }
2502
2503
2504 /*
2505  * Process events
2506  */
2507 static errr CheckEvent(bool wait)
2508 {
2509         term_data *old_td = (term_data*)(Term->data);
2510
2511         XEvent xev_body, *xev = &xev_body;
2512
2513         term_data *td = NULL;
2514         infowin *iwin = NULL;
2515
2516         int i;
2517
2518 #ifdef USE_XIM
2519  redo_checkevent:
2520 #endif
2521
2522         /* Do not wait unless requested */
2523         if (!wait && !XPending(Metadpy->dpy)) return (1);
2524
2525         /*
2526          * Hack - redraw the selection, if needed.
2527          * This doesn't actually check that one of its squares was drawn to,
2528          * only that this may have happened.
2529          */
2530         if (s_ptr->select && !s_ptr->drawn) mark_selection();
2531
2532         /* Load the Event */
2533         XNextEvent(Metadpy->dpy, xev);
2534
2535 #ifdef USE_XIM
2536 /* #define DEBUG_EVENT */
2537 #ifdef DEBUG_EVENT
2538         {
2539                 printf("event: type=%d", xev->type);
2540                 switch(xev->type){
2541                 case KeyPress:
2542                         printf("(KeyPress), keycode=%X", xev->xkey.keycode);
2543                         break;
2544                 case FocusIn:
2545                         printf("(FocusIn)");
2546                         break;
2547                 case FocusOut:
2548                         printf("(FocusOut)");
2549                         break;
2550                 case ReparentNotify:
2551                         printf("(ReparentNotify)");
2552                         break;
2553                 case ConfigureNotify:
2554                         printf("(ConfigureNotify)");
2555                         break;
2556                 case MapNotify:
2557                         printf("(MapNotify)");
2558                         break;
2559                 case Expose:
2560                         printf("(Expose)");
2561                         break;
2562                 case ClientMessage:
2563                         printf("(ClientMessage)");
2564                         break;
2565                 }
2566                         
2567         }
2568 #endif
2569         if (XFilterEvent(xev, xev->xany.window)
2570                 /*XFilterEvent(xev, (data[0].win)->win)*/){
2571 #ifdef DEBUG_EVENT
2572                 printf(", [filtered by IM]\n");
2573 #endif
2574                 goto redo_checkevent;
2575         }
2576 #ifdef DEBUG_EVENT
2577         printf("\n");
2578 #endif
2579 #endif
2580
2581         /* Notice new keymaps */
2582         if (xev->type == MappingNotify)
2583         {
2584                 XRefreshKeyboardMapping(&xev->xmapping);
2585                 return 0;
2586         }
2587
2588
2589         /* Scan the windows */
2590         for (i = 0; i < MAX_TERM_DATA; i++)
2591         {
2592                 if (!data[i].win) continue;
2593                 if (xev->xany.window == data[i].win->win)
2594                 {
2595                         td = &data[i];
2596                         iwin = td->win;
2597                         break;
2598                 }
2599         }
2600
2601         /* Unknown window */
2602         if (!td || !iwin) return (0);
2603
2604
2605         /* Hack -- activate the Term */
2606         Term_activate(&td->t);
2607
2608         /* Hack -- activate the window */
2609         Infowin_set(iwin);
2610
2611
2612         /* Switch on the Type */
2613         switch (xev->type)
2614         {
2615                 case ButtonPress:
2616                 case ButtonRelease:
2617                 {
2618                         bool press = (xev->type == ButtonPress);
2619
2620                         /* Where is the mouse */
2621                         int x = xev->xbutton.x;
2622                         int y = xev->xbutton.y;
2623
2624                         int z;
2625
2626                         /* Which button is involved */
2627                         if (xev->xbutton.button == Button1) z = 1;
2628                         else if (xev->xbutton.button == Button2) z = 2;
2629                         else if (xev->xbutton.button == Button3) z = 3;
2630                         else if (xev->xbutton.button == Button4) z = 4;
2631                         else if (xev->xbutton.button == Button5) z = 5;
2632                         else z = 0;
2633
2634                         /* XXX Handle */
2635                         handle_button(xev->xbutton.time, x, y, z, press);
2636
2637                         break;
2638                 }
2639
2640                 case EnterNotify:
2641                 case LeaveNotify:
2642                 {
2643                         /* XXX Handle */
2644
2645                         break;
2646                 }
2647
2648                 case MotionNotify:
2649                 {
2650                         /* Where is the mouse */
2651                         int x = xev->xmotion.x;
2652                         int y = xev->xmotion.y;
2653                         unsigned int z = xev->xmotion.state;
2654
2655                         /* Convert to co-ordinates Angband understands. */
2656                         pixel_to_square(&x, &y, x, y);
2657
2658                         /* Highlight the current square, if appropriate. */
2659                         /* highlight_square(window, y, x); */
2660
2661                         /* Alter the selection if appropriate. */
2662                         copy_x11_cont(x, y, z);
2663
2664                         /* XXX Handle */
2665
2666                         break;
2667                 }
2668
2669                 case SelectionNotify:
2670                 {
2671                         paste_x11_accept(&(xev->xselection));
2672                         break;
2673                 }
2674
2675                 case SelectionRequest:
2676                 {
2677                         paste_x11_send(&(xev->xselectionrequest));
2678                         break;
2679                 }
2680
2681                 case SelectionClear:
2682                 {
2683                         s_ptr->select = FALSE;
2684                         mark_selection();
2685                         break;
2686                 }
2687
2688                 case KeyRelease:
2689                 {
2690                         /* Nothing */
2691                         break;
2692                 }
2693
2694                 case KeyPress:
2695                 {
2696                         /* Hack -- use "old" term */
2697                         Term_activate(&old_td->t);
2698
2699                         /* Process the key */
2700                         react_keypress(&(xev->xkey));
2701
2702                         break;
2703                 }
2704
2705                 case Expose:
2706                 {
2707                         int x1, x2, y1, y2;
2708                         
2709                         /* Ignore "extra" exposes */
2710                         /*if (xev->xexpose.count) break;*/
2711
2712                         /* Clear the window */
2713                         /*Infowin_wipe();*/
2714                         
2715                         x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
2716                         x2 = (xev->xexpose.x + xev->xexpose.width -
2717                                  Infowin->ox)/Infofnt->wid;
2718                         
2719                         y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
2720                         y2 = (xev->xexpose.y + xev->xexpose.height -
2721                                  Infowin->oy)/Infofnt->hgt;
2722                         
2723                         Term_redraw_section(x1, y1, x2, y2);
2724
2725                         /* Redraw */
2726                         /*Term_redraw();*/
2727
2728                         break;
2729                 }
2730
2731                 case MapNotify:
2732                 {
2733                         Infowin->mapped = 1;
2734                         Term->mapped_flag = TRUE;
2735                         break;
2736                 }
2737
2738                 case UnmapNotify:
2739                 {
2740                         Infowin->mapped = 0;
2741                         Term->mapped_flag = FALSE;
2742                         break;
2743                 }
2744
2745                 /* Move and/or Resize */
2746                 case ConfigureNotify:
2747                 {
2748                         int cols, rows, wid, hgt;
2749
2750                         int ox = Infowin->ox;
2751                         int oy = Infowin->oy;
2752
2753                         /* Save the new Window Parms */
2754                         Infowin->x = xev->xconfigure.x;
2755                         Infowin->y = xev->xconfigure.y;
2756                         Infowin->w = xev->xconfigure.width;
2757                         Infowin->h = xev->xconfigure.height;
2758
2759                         /* Determine "proper" number of rows/cols */
2760                         cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2761                         rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2762
2763                         /* Hack -- minimal size */
2764                         if (cols < 1) cols = 1;
2765                         if (rows < 1) rows = 1;
2766
2767                         if (td == &data[0])
2768                         {
2769                                 /* Hack the main window must be at least 80x24 */
2770                                 if (cols < 80) cols = 80;
2771                                 if (rows < 24) rows = 24;
2772                         }
2773
2774                         /* Desired size of window */
2775                         wid = cols * td->fnt->wid + (ox + ox);
2776                         hgt = rows * td->fnt->hgt + (oy + oy);
2777
2778                         /* Resize the Term (if needed) */
2779                         Term_resize(cols, rows);
2780
2781                         /* Resize the windows if any "change" is needed */
2782                         if ((Infowin->w != wid) || (Infowin->h != hgt))
2783                         {
2784                                 /* Resize window */
2785                                 Infowin_set(td->win);
2786                                 Infowin_resize(wid, hgt);
2787                         }
2788
2789                         break;
2790                 }
2791 #ifdef USE_XIM
2792                 case FocusIn:
2793                 {
2794                         if(iwin->xic){
2795                                 XSetICFocus(iwin->xic);
2796                         }
2797                         Focuswin = iwin;
2798                         break;
2799                 }
2800                 case FocusOut:
2801                 {
2802                         if(iwin->xic){
2803                                 XUnsetICFocus(iwin->xic);
2804                         }
2805                         /* Focuswin = NULL;*/
2806                         break;
2807                 }
2808 #endif
2809         }
2810
2811
2812         /* Hack -- Activate the old term */
2813         Term_activate(&old_td->t);
2814
2815         /* Hack -- Activate the proper window */
2816         Infowin_set(old_td->win);
2817
2818
2819         /* Success */
2820         return (0);
2821 }
2822
2823
2824 #ifdef USE_SOUND
2825
2826 /*
2827  * An array of sound file names
2828  */
2829 static cptr sound_file[SOUND_MAX];
2830
2831 /*
2832  * Check for existance of a file
2833  */
2834 static bool check_file(cptr s)
2835 {
2836         FILE *fff;
2837
2838         fff = fopen(s, "r");
2839         if (!fff) return (FALSE);
2840         
2841         fclose(fff);
2842         return (TRUE);
2843 }
2844
2845 /*
2846  * Initialize sound
2847  */
2848 static void init_sound(void)
2849 {
2850         int i;
2851         char wav[128];
2852         char buf[1024];
2853         char dir_xtra_sound[1024];
2854                 
2855         /* Build the "sound" path */
2856         path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
2857                 
2858         /* Prepare the sounds */
2859         for (i = 1; i < SOUND_MAX; i++)
2860         {
2861                 /* Extract name of sound file */
2862                 sprintf(wav, "%s.wav", angband_sound_name[i]);
2863                 
2864                 /* Access the sound */
2865                 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
2866                 
2867                 /* Save the sound filename, if it exists */
2868                 if (check_file(buf)) sound_file[i] = string_make(buf);
2869         }
2870         use_sound = TRUE;
2871         return;
2872 }
2873
2874 /*
2875  * Hack -- make a sound
2876  */
2877 static errr Term_xtra_x11_sound(int v)
2878 {
2879         char buf[1024];
2880         
2881         /* Sound disabled */
2882         if (!use_sound) return (1);
2883         
2884         /* Illegal sound */
2885         if ((v < 0) || (v >= SOUND_MAX)) return (1);
2886         
2887         /* Unknown sound */
2888         if (!sound_file[v]) return (1);
2889         
2890         sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
2891         
2892         return (system(buf) < 0);
2893         
2894 }
2895 #endif /* USE_SOUND */
2896
2897
2898 /*
2899  * Handle "activation" of a term
2900  */
2901 static errr Term_xtra_x11_level(int v)
2902 {
2903         term_data *td = (term_data*)(Term->data);
2904
2905         /* Handle "activate" */
2906         if (v)
2907         {
2908                 /* Activate the window */
2909                 Infowin_set(td->win);
2910
2911                 /* Activate the font */
2912                 Infofnt_set(td->fnt);
2913 #ifdef USE_JP_FONTSTRUCT
2914                 Infokfnt_set(td->kfnt);
2915 #endif
2916         }
2917
2918         /* Success */
2919         return (0);
2920 }
2921
2922
2923 /*
2924  * React to changes
2925  */
2926 static errr Term_xtra_x11_react(void)
2927 {
2928         int i;
2929         
2930         if (Metadpy->color)
2931         {
2932                 /* Check the colors */
2933                 for (i = 0; i < 256; i++)
2934                 {
2935                         if ((color_table[i][0] != angband_color_table[i][0]) ||
2936                             (color_table[i][1] != angband_color_table[i][1]) ||
2937                             (color_table[i][2] != angband_color_table[i][2]) ||
2938                             (color_table[i][3] != angband_color_table[i][3]))
2939                         {
2940                                 Pixell pixel;
2941
2942                                 /* Save new values */
2943                                 color_table[i][0] = angband_color_table[i][0];
2944                                 color_table[i][1] = angband_color_table[i][1];
2945                                 color_table[i][2] = angband_color_table[i][2];
2946                                 color_table[i][3] = angband_color_table[i][3];
2947
2948                                 /* Create pixel */
2949                                 pixel = create_pixel(Metadpy->dpy,
2950                                                      color_table[i][1],
2951                                                      color_table[i][2],
2952                                                      color_table[i][3]);
2953
2954                                 /* Change the foreground */
2955                                 Infoclr_set(clr[i]);
2956                                 Infoclr_change_fg(pixel);
2957                         }
2958                 }
2959         }
2960
2961         /* Success */
2962         return (0);
2963 }
2964
2965
2966 /*
2967  * Handle a "special request"
2968  */
2969 static errr Term_xtra_x11(int n, int v)
2970 {
2971         /* Handle a subset of the legal requests */
2972         switch (n)
2973         {
2974                 /* Make a noise */
2975                 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
2976
2977 #ifdef USE_SOUND
2978                 /* Make a special sound */
2979                 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
2980 #endif
2981
2982                 /* Flush the output XXX XXX */
2983                 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
2984
2985                 /* Process random events XXX */
2986                 case TERM_XTRA_BORED: return (CheckEvent(0));
2987
2988                 /* Process Events XXX */
2989                 case TERM_XTRA_EVENT: return (CheckEvent(v));
2990
2991                 /* Flush the events XXX */
2992                 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
2993
2994                 /* Handle change in the "level" */
2995                 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
2996
2997                 /* Clear the screen */
2998                 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
2999
3000                 /* Delay for some milliseconds */
3001                 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
3002
3003                 /* React to changes */
3004                 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
3005         }
3006
3007         /* Unknown */
3008         return (1);
3009 }
3010
3011
3012 /*
3013  * Draw the cursor as an inverted rectangle.
3014  *
3015  * Consider a rectangular outline like "main-mac.c".  XXX XXX
3016  */
3017 static errr Term_curs_x11(int x, int y)
3018 {
3019         if (use_graphics)
3020         {
3021                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3022                                x * Infofnt->wid + Infowin->ox,
3023                                y * Infofnt->hgt + Infowin->oy,
3024                                Infofnt->wid - 1, Infofnt->hgt - 1);
3025                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3026                                x * Infofnt->wid + Infowin->ox + 1,
3027                                y * Infofnt->hgt + Infowin->oy + 1,
3028                                Infofnt->wid - 3, Infofnt->hgt - 3);
3029         }
3030         else
3031         {
3032                 /* Draw the cursor */
3033                 Infoclr_set(xor);
3034
3035                 /* Hilite the cursor character */
3036                 Infofnt_text_non(x, y, " ", 1);
3037         }
3038
3039         /* Success */
3040         return (0);
3041 }
3042
3043
3044 /*
3045  * Draw the double width cursor
3046  */
3047 static errr Term_bigcurs_x11(int x, int y)
3048 {
3049         if (use_graphics)
3050         {
3051                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3052                                x * Infofnt->wid + Infowin->ox,
3053                                y * Infofnt->hgt + Infowin->oy,
3054                                Infofnt->twid - 1, Infofnt->hgt - 1);
3055                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3056                                x * Infofnt->wid + Infowin->ox + 1,
3057                                y * Infofnt->hgt + Infowin->oy + 1,
3058                                Infofnt->twid - 3, Infofnt->hgt - 3);
3059         }
3060         else
3061         {
3062                 /* Draw the cursor */
3063                 Infoclr_set(xor);
3064
3065                 /* Hilite the cursor character */
3066                 Infofnt_text_non(x, y, "  ", 2);
3067         }
3068         /* Success */
3069         return (0);
3070 }
3071
3072
3073 /*
3074  * Erase some characters.
3075  */
3076 static errr Term_wipe_x11(int x, int y, int n)
3077 {
3078         /* Erase (use black) */
3079         Infoclr_set(clr[TERM_DARK]);
3080
3081         /* Mega-Hack -- Erase some space */
3082         Infofnt_text_non(x, y, "", n);
3083
3084         /* Redraw the selection if any, as it may have been obscured. (later) */
3085         s_ptr->drawn = FALSE;
3086
3087         /* Success */
3088         return (0);
3089 }
3090
3091
3092 /*
3093  * Draw some textual characters.
3094  */
3095 static errr Term_text_x11(int x, int y, int n, byte a, cptr s)
3096 {
3097         /* Draw the text */
3098         Infoclr_set(clr[a]);
3099
3100         /* Draw the text */
3101         Infofnt_text_std(x, y, s, n);
3102
3103         /* Redraw the selection if any, as it may have been obscured. (later) */
3104         s_ptr->drawn = FALSE;
3105
3106         /* Success */
3107         return (0);
3108 }
3109
3110
3111 #ifdef USE_GRAPHICS
3112
3113 /*
3114  * Draw some graphical characters.
3115  */
3116 static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
3117 {
3118         int i, x1, y1;
3119
3120         byte a;
3121         char c;
3122
3123         byte ta;
3124         char tc;
3125
3126         int x2, y2;
3127         int k,l;
3128
3129         unsigned long pixel, blank;
3130
3131         term_data *td = (term_data*)(Term->data);
3132
3133         y *= Infofnt->hgt;
3134         x *= Infofnt->wid;
3135
3136         /* Add in affect of window boundaries */
3137         y += Infowin->oy;
3138         x += Infowin->ox;
3139
3140         for (i = 0; i < n; ++i, x += td->fnt->wid)
3141         {
3142                 a = *ap++;
3143                 c = *cp++;
3144
3145                 /* For extra speed - cache these values */
3146                 x1 = (c&0x7F) * td->fnt->twid;
3147                 y1 = (a&0x7F) * td->fnt->hgt;
3148
3149                 /* Illegal tile index */
3150                 if (td->tiles->width < x1 + td->fnt->wid ||
3151                     td->tiles->height < y1 + td->fnt->hgt)
3152                 {
3153                         /* Draw black square */
3154                         XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc,
3155                                        x, y, 
3156                                        td->fnt->twid, td->fnt->hgt);
3157
3158                         /* Skip drawing tile */
3159                         continue;
3160                 }
3161
3162                 ta = *tap++;
3163                 tc = *tcp++;
3164
3165                 /* For extra speed - cache these values */
3166                 x2 = (tc&0x7F) * td->fnt->twid;
3167                 y2 = (ta&0x7F) * td->fnt->hgt;
3168                 
3169                 /* Optimise the common case */
3170                 if (((x1 == x2) && (y1 == y2)) ||
3171                     !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
3172                     td->tiles->width < x2 + td->fnt->wid ||
3173                     td->tiles->height < y2 + td->fnt->hgt)
3174                 {
3175                         /* Draw object / terrain */
3176                         XPutImage(Metadpy->dpy, td->win->win,
3177                                 clr[0]->gc,
3178                                 td->tiles,
3179                                 x1, y1,
3180                                 x, y,
3181                                 td->fnt->twid, td->fnt->hgt);   
3182                 }
3183                 else
3184                 {
3185
3186                         /* Mega Hack^2 - assume the top left corner is "black" */
3187                         blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
3188
3189                         for (k = 0; k < td->fnt->twid; k++)
3190                         {
3191                                 for (l = 0; l < td->fnt->hgt; l++)
3192                                 {
3193                                         /* If mask set... */
3194                                         if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
3195                                         {
3196                                                 /* Output from the terrain */
3197                                                 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
3198                                         }
3199                                         
3200                                         /* Store into the temp storage. */
3201                                         XPutPixel(td->TmpImage, k, l, pixel);
3202                                 }
3203                         }
3204
3205
3206                         /* Draw to screen */
3207
3208                         XPutImage(Metadpy->dpy, td->win->win,
3209                               clr[0]->gc,
3210                              td->TmpImage,
3211                              0, 0, x, y,
3212                              td->fnt->twid, td->fnt->hgt);
3213                 }
3214         }
3215
3216         /* Redraw the selection if any, as it may have been obscured. (later) */
3217         s_ptr->drawn = FALSE;
3218
3219         /* Success */
3220         return (0);
3221 }
3222
3223 #endif /* USE_GRAPHICS */
3224
3225 #ifdef USE_XIM
3226 static void IMDestroyCallback(XIM, XPointer, XPointer);
3227
3228 static void
3229 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
3230 {
3231         XIM xim;
3232         XIMCallback ximcallback;
3233         XIMStyles *xim_styles = NULL;
3234         int i;
3235
3236         /* Unused */
3237         (void)unused1;
3238         (void)unused2;
3239
3240         xim = XOpenIM(display, NULL, NULL, NULL);
3241         if(!xim){
3242                 printf("can't open IM\n");
3243                 return;
3244         }
3245
3246         /* initialize destroy callback */
3247         ximcallback.callback = IMDestroyCallback;
3248         ximcallback.client_data = NULL;
3249         XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
3250
3251         /* set style (only "Root" is supported yet...) */
3252         XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
3253         for (i = 0; i < xim_styles->count_styles; i++){
3254                 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
3255         }
3256         if(i >= xim_styles->count_styles){
3257                 printf("Sorry, your IM does not support 'Root' preedit style...\n");
3258                 XCloseIM(xim);
3259                 return;
3260         }
3261         XFree(xim_styles);
3262
3263         Metadpy->xim = xim;
3264
3265         for (i = 0; i < MAX_TERM_DATA; i++)
3266         {
3267                 infowin *iwin = data[i].win;
3268                 if (!iwin) continue;
3269                 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
3270                 if(!iwin->xic){
3271                         printf("Can't create input context for Term%d\n", i);
3272                         continue;
3273                 }
3274                 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL){
3275 /*                      printf("Can't get XNFilterEvents\n"); */
3276                         iwin->xic_mask = 0L;
3277                 }
3278                 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
3279         }
3280
3281         return;
3282 }
3283
3284 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
3285 {
3286         int i;
3287
3288         /* Unused */
3289         (void)xim;
3290         (void)client_data;
3291
3292         if (call_data == NULL){
3293                 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3294         }
3295
3296         for(i = 0; i < MAX_TERM_DATA; i++)
3297         {
3298                 infowin *iwin = data[i].win;
3299                 if(!iwin) continue;
3300                 if(iwin->xic_mask){
3301                         XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
3302                         iwin->xic_mask = 0L;
3303                 }
3304                 iwin->xic = NULL;
3305         }
3306
3307         Metadpy->xim = NULL;
3308 }
3309 #endif
3310
3311 /*
3312  * Initialize a term_data
3313  */
3314 static errr term_data_init(term_data *td, int i)
3315 {
3316         term *t = &td->t;
3317
3318         cptr name = angband_term_name[i];
3319
3320         cptr font;
3321 #ifdef USE_JP_FONTSTRUCT
3322         cptr kfont;
3323 #endif
3324
3325
3326         int x = 0;
3327         int y = 0;
3328
3329         int cols = 80;
3330         int rows = 24;
3331
3332         int ox = 1;
3333         int oy = 1;
3334
3335         int wid, hgt, num;
3336
3337         char buf[80];
3338
3339         cptr str;
3340
3341         int val;
3342
3343         XClassHint *ch;
3344
3345         char res_name[20];
3346         char res_class[20];
3347
3348         XSizeHints *sh;
3349 #ifdef USE_XIM
3350         XWMHints *wh;
3351 #endif
3352
3353         /* Window specific font name */
3354         sprintf(buf, "ANGBAND_X11_FONT_%d", i);
3355
3356         /* Check environment for that font */
3357         font = getenv(buf);
3358
3359         /* Check environment for "base" font */
3360         if (!font) font = getenv("ANGBAND_X11_FONT");
3361
3362         /* No environment variables, use default font */
3363         if (!font)
3364         {
3365                 switch (i)
3366                 {
3367                         case 0:
3368                         {
3369                                 font = DEFAULT_X11_FONT_0;
3370                         }
3371                         break;
3372                         case 1:
3373                         {
3374                                 font = DEFAULT_X11_FONT_1;
3375                         }
3376                         break;
3377                         case 2:
3378                         {
3379                                 font = DEFAULT_X11_FONT_2;
3380                         }
3381                         break;
3382                         case 3:
3383                         {
3384                                 font = DEFAULT_X11_FONT_3;
3385                         }
3386                         break;
3387                         case 4:
3388                         {
3389                                 font = DEFAULT_X11_FONT_4;
3390                         }
3391                         break;
3392                         case 5:
3393                         {
3394                                 font = DEFAULT_X11_FONT_5;
3395                         }
3396                         break;
3397                         case 6:
3398                         {
3399                                 font = DEFAULT_X11_FONT_6;
3400                         }
3401                         break;
3402                         case 7:
3403                         {
3404                                 font = DEFAULT_X11_FONT_7;
3405                         }
3406                         break;
3407                         default:
3408                         {
3409                                 font = DEFAULT_X11_FONT;
3410                         }
3411                 }
3412         }
3413
3414 #ifdef USE_JP_FONTSTRUCT
3415         /* Window specific font name */
3416         sprintf(buf, "ANGBAND_X11_KFONT_%d", i);
3417
3418         /* Check environment for that font */
3419         kfont = getenv(buf);
3420
3421         /* Check environment for "base" font */
3422         if (!kfont) kfont = getenv("ANGBAND_X11_KFONT");
3423
3424         /* No environment variables, use default font */
3425         if (!kfont)
3426         {
3427                 switch (i)
3428                 {
3429                         case 0:
3430                         {
3431                                 kfont = DEFAULT_X11_KFONT_0;
3432                         }
3433                         break;
3434                         case 1:
3435                         {
3436                                 kfont = DEFAULT_X11_KFONT_1;
3437                         }
3438                         break;
3439                         case 2:
3440                         {
3441                                 kfont = DEFAULT_X11_KFONT_2;
3442                         }
3443                         break;
3444                         case 3:
3445                         {
3446                                 kfont = DEFAULT_X11_KFONT_3;
3447                         }
3448                         break;
3449                         case 4:
3450                         {
3451                                 kfont = DEFAULT_X11_KFONT_4;
3452                         }
3453                         break;
3454                         case 5:
3455                         {
3456                                 kfont = DEFAULT_X11_KFONT_5;
3457                         }
3458                         break;
3459                         case 6:
3460                         {
3461                                 kfont = DEFAULT_X11_KFONT_6;
3462                         }
3463                         break;
3464                         case 7:
3465                         {
3466                                 kfont = DEFAULT_X11_KFONT_7;
3467                         }
3468                         break;
3469                         default:
3470                         {
3471                                 kfont = DEFAULT_X11_KFONT;
3472                         }
3473                 }
3474         }
3475 #endif
3476         /* Window specific location (x) */
3477         sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
3478         str = getenv(buf);
3479         x = (str != NULL) ? atoi(str) : -1;
3480
3481         /* Window specific location (y) */
3482         sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
3483         str = getenv(buf);
3484         y = (str != NULL) ? atoi(str) : -1;
3485
3486
3487         /* Window specific cols */
3488         sprintf(buf, "ANGBAND_X11_COLS_%d", i);
3489         str = getenv(buf);
3490         val = (str != NULL) ? atoi(str) : -1;
3491         if (val > 0) cols = val;
3492
3493         /* Window specific rows */
3494         sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
3495         str = getenv(buf);
3496         val = (str != NULL) ? atoi(str) : -1;
3497         if (val > 0) rows = val;
3498
3499         /* Hack the main window must be at least 80x24 */
3500         if (!i)
3501         {
3502                 if (cols < 80) cols = 80;
3503                 if (rows < 24) rows = 24;
3504         }
3505
3506         /* Window specific inner border offset (ox) */
3507         sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
3508         str = getenv(buf);
3509         val = (str != NULL) ? atoi(str) : -1;
3510         if (val > 0) ox = val;
3511
3512         /* Window specific inner border offset (oy) */
3513         sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
3514         str = getenv(buf);
3515         val = (str != NULL) ? atoi(str) : -1;
3516         if (val > 0) oy = val;
3517
3518
3519         /* Prepare the standard font */
3520 #ifdef USE_JP_FONTSTRUCT
3521         MAKE(td->fnt, infofnt);
3522         Infofnt_set(td->fnt);
3523         MAKE(td->kfnt, infofnt);
3524         Infokfnt_set(td->kfnt);
3525         Infofnt_init_data(font, kfont);
3526 #else
3527         MAKE(td->fnt, infofnt);
3528         Infofnt_set(td->fnt);
3529         Infofnt_init_data(font);
3530 #endif
3531
3532
3533         /* Hack -- key buffer size */
3534         num = ((i == 0) ? 1024 : 16);
3535
3536         /* Assume full size windows */
3537         wid = cols * td->fnt->wid + (ox + ox);
3538         hgt = rows * td->fnt->hgt + (oy + oy);
3539
3540         /* Create a top-window */
3541         MAKE(td->win, infowin);
3542         Infowin_set(td->win);
3543         Infowin_init_top(x, y, wid, hgt, 0,
3544                          Metadpy->fg, Metadpy->bg);
3545
3546         /* Ask for certain events */
3547 #if defined(USE_XIM)
3548         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
3549 #else
3550         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
3551 #endif
3552
3553         /* Set the window name */
3554         Infowin_set_name(name);
3555
3556         /* Save the inner border */
3557         Infowin->ox = ox;
3558         Infowin->oy = oy;
3559
3560         /* Make Class Hints */
3561         ch = XAllocClassHint();
3562
3563         if (ch == NULL) quit("XAllocClassHint failed");
3564
3565         strcpy(res_name, name);
3566         res_name[0] = FORCELOWER(res_name[0]);
3567         ch->res_name = res_name;
3568
3569         strcpy(res_class, "Angband");
3570         ch->res_class = res_class;
3571
3572         XSetClassHint(Metadpy->dpy, Infowin->win, ch);
3573
3574         /* Make Size Hints */
3575         sh = XAllocSizeHints();
3576
3577         /* Oops */
3578         if (sh == NULL) quit("XAllocSizeHints failed");
3579
3580         /* Main window has a differing minimum size */
3581         if (i == 0)
3582         {
3583                 /* Main window min size is 80x24 */
3584                 sh->flags = PMinSize | PMaxSize;
3585                 sh->min_width = 80 * td->fnt->wid + (ox + ox);
3586                 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
3587                 sh->max_width = 255 * td->fnt->wid + (ox + ox);
3588                 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
3589         }
3590
3591         /* Other windows can be shrunk to 1x1 */
3592         else
3593         {
3594                 /* Other windows */
3595                 sh->flags = PMinSize | PMaxSize;
3596                 sh->min_width = td->fnt->wid + (ox + ox);
3597                 sh->min_height = td->fnt->hgt + (oy + oy);
3598                 sh->max_width = 256 * td->fnt->wid + (ox + ox);
3599                 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
3600         }
3601
3602         /* Resize increment */
3603         sh->flags |= PResizeInc;
3604         sh->width_inc = td->fnt->wid;
3605         sh->height_inc = td->fnt->hgt;
3606
3607         /* Base window size */
3608         sh->flags |= PBaseSize;
3609         sh->base_width = (ox + ox);
3610         sh->base_height = (oy + oy);
3611
3612         /* Use the size hints */
3613         XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
3614
3615         /* Map the window */
3616         Infowin_map();
3617
3618 #ifdef USE_XIM
3619         /* Make WM Hints */
3620         wh = XAllocWMHints();
3621         if(wh == NULL) quit("XAllocWMHints failed");
3622         wh->flags = InputHint;
3623         wh->input = True;
3624         XSetWMHints(Metadpy->dpy, Infowin->win, wh);
3625 #endif
3626
3627         /* Move the window to requested location */
3628         if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
3629
3630
3631         /* Initialize the term */
3632         term_init(t, cols, rows, num);
3633
3634         /* Use a "soft" cursor */
3635         t->soft_cursor = TRUE;
3636
3637         /* Erase with "white space" */
3638         t->attr_blank = TERM_WHITE;
3639         t->char_blank = ' ';
3640
3641         /* Hooks */
3642         t->xtra_hook = Term_xtra_x11;
3643         t->curs_hook = Term_curs_x11;
3644         t->bigcurs_hook = Term_bigcurs_x11;
3645         t->wipe_hook = Term_wipe_x11;
3646         t->text_hook = Term_text_x11;
3647
3648         /* Save the data */
3649         t->data = td;
3650
3651         /* Activate (important) */
3652         Term_activate(t);
3653
3654         /* Success */
3655         return (0);
3656 }
3657
3658
3659 /*
3660  * Initialization function for an "X11" module to Angband
3661  */
3662 errr init_x11(int argc, char *argv[])
3663 {
3664         int i;
3665
3666         cptr dpy_name = "";
3667
3668         int num_term = 3;
3669
3670 #ifdef USE_GRAPHICS
3671
3672         char filename[1024];
3673
3674         int pict_wid = 0;
3675         int pict_hgt = 0;
3676
3677         char *TmpData;
3678 #endif /* USE_GRAPHICS */
3679
3680
3681         /* Parse args */
3682         for (i = 1; i < argc; i++)
3683         {
3684                 if (prefix(argv[i], "-d"))
3685                 {
3686                         dpy_name = &argv[i][2];
3687                         continue;
3688                 }
3689                 
3690 #ifdef USE_GRAPHICS
3691                 if (prefix(argv[i], "-s"))
3692                 {
3693                         smoothRescaling = FALSE;
3694                         continue;
3695                 }
3696
3697                 if (prefix(argv[i], "-a"))
3698                 {
3699                         arg_graphics = GRAPHICS_ADAM_BOLT;
3700                         continue;
3701                 }
3702
3703                 if (prefix(argv[i], "-o"))
3704                 {
3705                         arg_graphics = GRAPHICS_ORIGINAL;
3706                         continue;
3707                 }
3708
3709                 if (prefix(argv[i], "-b"))
3710                 {
3711                         arg_bigtile = use_bigtile = TRUE;
3712                         continue;
3713                 }
3714 #endif /* USE_GRAPHICS */
3715
3716                 if (prefix(argv[i], "-n"))
3717                 {
3718                         num_term = atoi(&argv[i][2]);
3719                         if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
3720                         else if (num_term < 1) num_term = 1;
3721                         continue;
3722                 }
3723
3724                 if (prefix(argv[i], "--"))
3725                 {
3726                         /* Ignore */
3727                         continue;
3728                 }
3729
3730                 plog_fmt("Ignoring option: %s", argv[i]);
3731         }
3732
3733 #ifdef USE_LOCALE
3734
3735 #ifdef JP
3736         /* Get locale information from environment variables */
3737         setlocale(LC_ALL, "");
3738
3739 #ifdef DEFAULT_LOCALE
3740         if(!strcmp(setlocale(LC_ALL, NULL), "C")){
3741                 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
3742                 setlocale(LC_ALL, DEFAULT_LOCALE);
3743         }
3744 #endif
3745
3746         if(!strcmp(setlocale(LC_ALL, NULL), "C"))
3747         {
3748                 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
3749         }
3750
3751         if(!XSupportsLocale()){
3752                 printf("can't support locale in X\n");
3753                 setlocale(LC_ALL, "C");
3754         }
3755 #else
3756         /* Set locale to "C" without using environment variables */
3757         setlocale(LC_ALL, "C");
3758 #endif /* JP */
3759
3760 #endif /* USE_LOCALE */
3761
3762
3763         /* Init the Metadpy if possible */
3764         if (Metadpy_init_name(dpy_name)) return (-1);
3765
3766
3767         /* Prepare cursor color */
3768         MAKE(xor, infoclr);
3769         Infoclr_set(xor);
3770         Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
3771
3772
3773         /* Prepare normal colors */
3774         for (i = 0; i < 256; ++i)
3775         {
3776                 Pixell pixel;
3777
3778                 MAKE(clr[i], infoclr);
3779
3780                 Infoclr_set(clr[i]);
3781
3782                 /* Acquire Angband colors */
3783                 color_table[i][0] = angband_color_table[i][0];
3784                 color_table[i][1] = angband_color_table[i][1];
3785                 color_table[i][2] = angband_color_table[i][2];
3786                 color_table[i][3] = angband_color_table[i][3];
3787
3788                 /* Default to monochrome */
3789                 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
3790
3791                 /* Handle color */
3792                 if (Metadpy->color)
3793                 {
3794                         /* Create pixel */
3795                         pixel = create_pixel(Metadpy->dpy,
3796                                              color_table[i][1],
3797                                              color_table[i][2],
3798                                              color_table[i][3]);
3799                 }
3800
3801                 /* Initialize the color */
3802                 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
3803         }
3804
3805
3806         /* Prepare required atoms. */
3807         set_atoms();
3808
3809
3810         /* Initialize the windows */
3811         for (i = 0; i < num_term; i++)
3812         {
3813                 term_data *td = &data[i];
3814
3815                 /* Initialize the term_data */
3816                 term_data_init(td, i);
3817
3818                 /* Save global entry */
3819                 angband_term[i] = Term;
3820         }
3821
3822         /* Raise the "Angband" window */
3823         Infowin_set(data[0].win);
3824         Infowin_raise();
3825
3826         /* Activate the "Angband" window screen */
3827         Term_activate(&data[0].t);
3828
3829 #ifdef USE_XIM
3830         {
3831                 char *p;
3832                 p = XSetLocaleModifiers("");
3833                 if(!p || !*p){
3834                         p = XSetLocaleModifiers("@im=");
3835                 }
3836 /*              printf("XMODIFIERS=\"%s\"\n", p); */
3837         }
3838         XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3839 #endif
3840
3841 #ifdef USE_SOUND
3842         /* initialize sound */
3843         if (arg_sound) init_sound();
3844 #endif
3845
3846 #ifdef USE_GRAPHICS
3847
3848         /* Try graphics */
3849         switch (arg_graphics)
3850         {
3851         case GRAPHICS_ORIGINAL:
3852                 /* Try the "8x8.bmp" file */
3853                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
3854
3855                 /* Use the "8x8.bmp" file if it exists */
3856                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3857                 {
3858                         /* Use graphics */
3859                         use_graphics = TRUE;
3860
3861                         pict_wid = pict_hgt = 8;
3862
3863                         ANGBAND_GRAF = "old";
3864                         break;
3865                 }
3866                 /* Fall through */
3867
3868         case GRAPHICS_ADAM_BOLT:
3869                 /* Try the "16x16.bmp" file */
3870                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
3871
3872                 /* Use the "16x16.bmp" file if it exists */
3873                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3874                 {
3875                         /* Use graphics */
3876                         use_graphics = TRUE;
3877
3878                         pict_wid = pict_hgt = 16;
3879
3880                         ANGBAND_GRAF = "new";
3881
3882                         break;
3883                 }
3884         }
3885
3886         /* Load graphics */
3887         if (use_graphics)
3888         {
3889                 Display *dpy = Metadpy->dpy;
3890
3891                 XImage *tiles_raw;
3892
3893                 /* Load the graphical tiles */
3894                 tiles_raw = ReadBMP(dpy, filename);
3895
3896                 /* Initialize the windows */
3897                 for (i = 0; i < num_term; i++)
3898                 {
3899                         term_data *td = &data[i];
3900
3901                         term *t = &td->t;
3902
3903                         /* Graphics hook */
3904                         t->pict_hook = Term_pict_x11;
3905
3906                         /* Use graphics sometimes */
3907                         t->higher_pict = TRUE;
3908
3909                         /* Resize tiles */
3910                         td->tiles =
3911                         ResizeImage(dpy, tiles_raw,
3912                                     pict_wid, pict_hgt,
3913                                     td->fnt->twid, td->fnt->hgt);
3914                 }
3915
3916                 /* Initialize the transparency masks */
3917                 for (i = 0; i < num_term; i++)
3918                 {
3919                         term_data *td = &data[i];
3920                         int ii, jj;
3921                         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
3922                         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
3923                         int total;
3924
3925
3926                         /* Determine total bytes needed for image */
3927                         ii = 1;
3928                         jj = (depth - 1) >> 2;
3929                         while (jj >>= 1) ii <<= 1;
3930                         total = td->fnt->twid * td->fnt->hgt * ii;
3931                         
3932                         
3933                         TmpData = (char *)malloc(total);
3934
3935                         td->TmpImage = XCreateImage(dpy,visual,depth,
3936                                 ZPixmap, 0, TmpData,
3937                                 td->fnt->twid, td->fnt->hgt, 8, 0);
3938
3939                 }
3940
3941                 /* Free tiles_raw? XXX XXX */
3942         }
3943
3944 #endif /* USE_GRAPHICS */
3945
3946
3947         /* Success */
3948         return (0);
3949 }
3950
3951 #endif /* USE_X11 */
3952