OSDN Git Service

Merge remote-tracking branch 'remotes/origin/MERFOLK'
[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         concptr 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, concptr 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(concptr 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(concptr 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 concptr 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(concptr 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(concptr 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(concptr name, concptr kname)
1413 #else
1414 static void Infofnt_init_data(concptr 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, concptr 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; char *kp = kanji;
1674                 char sbuf[1024];
1675                 my_strcpy(sbuf, str, sizeof(sbuf));
1676                 sp = sbuf;
1677                 iconv(cd, &sp, &inlen, &kp, &outlen);
1678                 iconv_close(cd);
1679
1680                 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
1681                                 Infoclr->gc, x, y, kanji, kp-kanji);
1682                 free(kanji);
1683 #else
1684                 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1685                                  x, y, str, len);
1686 #endif
1687 #endif
1688
1689         }
1690
1691
1692         /* Success */
1693         return (0);
1694 }
1695
1696
1697 /*
1698  * Painting where text would be
1699  */
1700 static errr Infofnt_text_non(int x, int y, concptr str, int len)
1701 {
1702         int w, h;
1703
1704
1705         /*** Find the width ***/
1706
1707         /* Negative length is a flag to count the characters in str */
1708         if (len < 0) len = strlen(str);
1709
1710         /* The total width will be 'len' chars * standard width */
1711         w = len * Infofnt->wid;
1712
1713
1714         /*** Find the X dimensions ***/
1715
1716         /* Line up with x at left edge of column 'x' */
1717         x = x * Infofnt->wid + Infowin->ox;
1718
1719
1720         /*** Find other dimensions ***/
1721
1722         /* Simply do 'Infofnt->hgt' (a single row) high */
1723         h = Infofnt->hgt;
1724
1725         /* Simply do "at top" in row 'y' */
1726         y = y * h + Infowin->oy;
1727
1728
1729         /*** Actually 'paint' the area ***/
1730
1731         /* Just do a Fill Rectangle */
1732         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
1733
1734         /* Success */
1735         return (0);
1736 }
1737
1738
1739
1740 /*************************************************************************/
1741
1742
1743 /*
1744  * Angband specific code follows... (ANGBAND)
1745  */
1746
1747
1748 /*
1749  * Hack -- cursor color
1750  */
1751 static infoclr *xor;
1752
1753 /*
1754  * Actual color table
1755  */
1756 static infoclr *clr[256];
1757
1758 /*
1759  * Color info (unused, red, green, blue).
1760  */
1761 static byte color_table[256][4];
1762
1763 /*
1764  * Forward declare
1765  */
1766 typedef struct term_data term_data;
1767
1768 /*
1769  * A structure for each "term"
1770  */
1771 struct term_data
1772 {
1773         term t;
1774
1775         infofnt *fnt;
1776 #ifdef USE_JP_FONTSTRUCT
1777         infofnt *kfnt;
1778 #endif
1779
1780
1781         infowin *win;
1782
1783 #ifdef USE_GRAPHICS
1784
1785         XImage *tiles;
1786
1787         /* Tempory storage for overlaying tiles. */
1788         XImage *TmpImage;
1789
1790 #endif
1791
1792 };
1793
1794
1795 /*
1796  * The number of term data structures
1797  */
1798 #define MAX_TERM_DATA 8
1799
1800 /*
1801  * The array of term data structures
1802  */
1803 static term_data data[MAX_TERM_DATA];
1804
1805
1806 /* Use short names for the most commonly used elements of various structures. */
1807 #define DPY (Metadpy->dpy)
1808 #define WIN (Infowin->win)
1809
1810
1811 /* Describe a set of co-ordinates. */
1812 typedef struct co_ord co_ord;
1813 struct co_ord
1814 {
1815         int x;
1816         int y;
1817 };
1818
1819
1820 /*
1821  * A special structure to store information about the text currently
1822  * selected.
1823  */
1824 typedef struct x11_selection_type x11_selection_type;
1825 struct x11_selection_type
1826 {
1827         bool select; /* The selection is currently in use. */
1828         bool drawn; /* The selection is currently displayed. */
1829         term *t; /* The window where the selection is found. */
1830         co_ord init; /* The starting co-ordinates. */
1831         co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1832         co_ord old; /* The previous end co-ordinates. */
1833         Time time; /* The time at which the selection was finalised. */
1834 };
1835
1836 static x11_selection_type s_ptr[1];
1837
1838
1839 /*
1840  * Process a keypress event
1841  *
1842  * Also appears in "main-xaw.c".
1843  */
1844 static void react_keypress(XKeyEvent *xev)
1845 {
1846         int i, n, mc, ms, mo, mx;
1847
1848         uint ks1;
1849
1850         XKeyEvent *ev = (XKeyEvent*)(xev);
1851
1852         KeySym ks;
1853
1854         char buf[128];
1855         char msg[128];
1856
1857 #ifdef USE_XIM
1858         int valid_keysym = TRUE;
1859 #endif
1860
1861         /* Check for "normal" keypresses */
1862 #ifdef USE_XIM
1863         if(Focuswin && Focuswin->xic){
1864                 Status status;
1865                 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1866                 if(status == XBufferOverflow){
1867                         printf("Input is too long, and dropped\n");
1868                         return;
1869                 }
1870                 if(status != XLookupKeySym && status != XLookupBoth){
1871                         valid_keysym = FALSE;
1872                 }
1873         }else{
1874                 n = XLookupString(ev, buf, 125, &ks, NULL);
1875         }
1876 #else
1877         n = XLookupString(ev, buf, 125, &ks, NULL);
1878 #endif
1879
1880         /* Terminate */
1881         buf[n] = '\0';
1882
1883 #ifdef USE_XIM
1884         if(!valid_keysym){
1885                 /* Enqueue the normal key(s) */
1886                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1887
1888                 /* All done */
1889                 return;
1890         }
1891 #endif
1892
1893         /* Hack -- Ignore "modifier keys" */
1894         if (IsModifierKey(ks)) return;
1895
1896
1897         /* Hack -- convert into an unsigned int */
1898         ks1 = (uint)(ks);
1899
1900         /* Extract four "modifier flags" */
1901         mc = (ev->state & ControlMask) ? TRUE : FALSE;
1902         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1903         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1904         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1905
1906
1907         /* Normal keys with no modifiers */
1908         if (n && !mo && !mx && !IsSpecialKey(ks))
1909         {
1910                 /* Enqueue the normal key(s) */
1911                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1912
1913                 /* All done */
1914                 return;
1915         }
1916
1917
1918         /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1919         switch (ks1)
1920         {
1921                 case XK_Escape:
1922                 {
1923                         Term_keypress(ESCAPE);
1924                         return;
1925                 }
1926
1927                 case XK_Return:
1928                 {
1929                         Term_keypress('\r');
1930                         return;
1931                 }
1932
1933                 case XK_Tab:
1934                 {
1935                         Term_keypress('\t');
1936                         return;
1937                 }
1938
1939                 case XK_Delete:
1940                 {
1941                         Term_keypress(0x7f);
1942                         return;
1943                 }
1944                 case XK_BackSpace:
1945                 {
1946                         Term_keypress('\010');
1947                         return;
1948                 }
1949         }
1950
1951
1952         /* Hack -- Use the KeySym */
1953         if (ks)
1954         {
1955                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1956                         mc ? "N" : "", ms ? "S" : "",
1957                         mo ? "O" : "", mx ? "M" : "",
1958                         (unsigned long)(ks), 13);
1959         }
1960
1961         /* Hack -- Use the Keycode */
1962         else
1963         {
1964                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1965                         mc ? "N" : "", ms ? "S" : "",
1966                         mo ? "O" : "", mx ? "M" : "",
1967                         ev->keycode, 13);
1968         }
1969
1970         /* Enqueue the "macro trigger" string */
1971         for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1972
1973
1974         /* Hack -- auto-define macros as needed */
1975         if (n && (macro_find_exact(msg) < 0))
1976         {
1977                 /* Create a macro */
1978                 macro_add(msg, buf);
1979         }
1980 }
1981
1982
1983 /*
1984  * Find the square a particular pixel is part of.
1985  */
1986 static void pixel_to_square(int * const x, int * const y,
1987         const int ox, const int oy)
1988 {
1989         (*x) = (ox - Infowin->ox) / Infofnt->wid;
1990         (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1991 }
1992
1993 /*
1994  * Find the pixel at the top-left corner of a square.
1995  */
1996 static void square_to_pixel(int * const x, int * const y,
1997         const int ox, const int oy)
1998 {
1999         (*x) = ox * Infofnt->wid + Infowin->ox;
2000         (*y) = oy * Infofnt->hgt + Infowin->oy;
2001 }
2002
2003 /*
2004  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
2005  */
2006 static void sort_co_ord(co_ord *min, co_ord *max,
2007         const co_ord *b, const co_ord *a)
2008 {
2009         min->x = MIN(a->x, b->x);
2010         min->y = MIN(a->y, b->y);
2011         max->x = MAX(a->x, b->x);
2012         max->y = MAX(a->y, b->y);
2013 }
2014
2015 /*
2016  * Remove the selection by redrawing it.
2017  */
2018 static void mark_selection_clear(int x1, int y1, int x2, int y2)
2019 {
2020         Term_redraw_section(x1,y1,x2,y2);
2021 }
2022
2023 /*
2024  * Select an area by drawing a grey box around it.
2025  * NB. These two functions can cause flicker as the selection is modified,
2026  * as the game redraws the entire marked section.
2027  */
2028 static void mark_selection_mark(int x1, int y1, int x2, int y2)
2029 {
2030         square_to_pixel(&x1, &y1, x1, y1);
2031         square_to_pixel(&x2, &y2, x2, y2);
2032         XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
2033                 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
2034 }
2035
2036 /*
2037  * Mark a selection by drawing boxes around it (for now).
2038  */
2039 static void mark_selection(void)
2040 {
2041         co_ord min, max;
2042         term *old = Term;
2043         bool draw = s_ptr->select;
2044         bool clear = s_ptr->drawn;
2045
2046         /* Open the correct term if necessary. */
2047         if (s_ptr->t != old) Term_activate(s_ptr->t);
2048
2049         if (clear)
2050         {
2051                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
2052                 mark_selection_clear(min.x, min.y, max.x, max.y);
2053         }
2054         if (draw)
2055         {
2056                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2057                 mark_selection_mark(min.x, min.y, max.x, max.y);
2058         }
2059
2060         /* Finish on the current term. */
2061         if (s_ptr->t != old) Term_activate(old);
2062
2063         s_ptr->old.x = s_ptr->cur.x;
2064         s_ptr->old.y = s_ptr->cur.y;
2065         s_ptr->drawn = s_ptr->select;
2066 }
2067
2068 /*
2069  * Forget a selection for one reason or another.
2070  */
2071 static void copy_x11_release(void)
2072 {
2073         /* Deselect the current selection. */
2074         s_ptr->select = FALSE;
2075
2076         /* Remove its graphical represesntation. */
2077         mark_selection();
2078 }
2079
2080 /*
2081  * Start to select some text on the screen.
2082  */
2083 static void copy_x11_start(int x, int y)
2084 {
2085         if (s_ptr->select) copy_x11_release();
2086
2087         /* Remember where the selection started. */
2088         s_ptr->t = Term;
2089         s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
2090         s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
2091 }
2092
2093 /*
2094  * Respond to movement of the mouse when selecting text.
2095  */
2096 static void copy_x11_cont(int x, int y, unsigned int buttons)
2097 {
2098         /* Use the nearest square within bounds if the mouse is outside. */
2099         x = MIN(MAX(x, 0), Term->wid-1);
2100         y = MIN(MAX(y, 0), Term->hgt-1);
2101
2102         /* The left mouse button isn't pressed. */
2103         if (~buttons & Button1Mask) return;
2104
2105         /* Not a selection in this window. */
2106         if (s_ptr->t != Term) return;
2107
2108         /* Not enough movement. */
2109         if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
2110
2111         /* Something is being selected. */
2112         s_ptr->select = TRUE;
2113
2114         /* Track the selection. */
2115         s_ptr->cur.x = x;
2116         s_ptr->cur.y = y;
2117
2118         /* Hack - display it inefficiently. */
2119         mark_selection();
2120 }
2121
2122 /*
2123  * Respond to release of the left mouse button by putting the selected text in
2124  * the primary buffer.
2125  */
2126 static void copy_x11_end(const Time time)
2127 {
2128         /* No selection. */
2129         if (!s_ptr->select) return;
2130
2131         /* Not a selection in this window. */
2132         if (s_ptr->t != Term) return;
2133
2134         /* Remember when the selection was finalised. */
2135         s_ptr->time = time;
2136
2137         /* Acquire the primary selection. */
2138         XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
2139         if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
2140         {
2141                 /* Failed to acquire the selection, so forget it. */
2142                 /* bell("Failed to acquire primary buffer."); */
2143                 s_ptr->select = FALSE;
2144                 mark_selection();
2145         }
2146 }
2147
2148
2149 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
2150
2151 /*
2152  * Set the required variable atoms at start-up to avoid errors later.
2153  */
2154 static void set_atoms(void)
2155 {
2156         xa_targets = XInternAtom(DPY, "TARGETS", False);
2157         xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
2158         xa_text = XInternAtom(DPY, "TEXT", False);
2159         xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
2160 }
2161
2162
2163 static Atom request_target = 0;
2164
2165 /*
2166  * Send a message to request that the PRIMARY buffer be sent here.
2167  */
2168 static void paste_x11_request(Atom target, const Time time)
2169 {
2170         /*
2171          * It's from some sample programs on the web.
2172          * What does it mean? -- XXX
2173          */
2174         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2175
2176         /* Check the owner. */
2177         if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
2178         {
2179                 /* No selection. */
2180                 /* bell("No selection found."); */
2181                 return;
2182         }
2183
2184         request_target = target;
2185     
2186         /* Request the event */
2187         XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
2188 }
2189
2190
2191 /*
2192  * Add the contents of the PRIMARY buffer to the input queue.
2193  *
2194  * Hack - This doesn't use the "time" of the event, and so accepts anything a
2195  * client tries to send it.
2196  */
2197 static void paste_x11_accept(const XSelectionEvent *ptr)
2198 {
2199         unsigned long left;
2200         const long offset = 0;
2201         const long length = 32000;
2202         XTextProperty xtextproperty;
2203         errr err = 0;
2204
2205         /*
2206          * It's from some sample programs on the web.
2207          * What does it mean? -- XXX
2208          */
2209         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2210
2211
2212         /* Failure. */
2213         if (ptr->property == None)
2214         {
2215                 if (request_target == xa_compound_text)
2216                 {
2217                         /* Re-request as STRING */
2218                         paste_x11_request(XA_STRING, ptr->time);
2219                 }
2220                 else
2221                 {
2222                         request_target = 0;
2223                         plog("Paste failure (remote client could not send).");
2224                 }
2225                 return;
2226         }
2227
2228         if (ptr->selection != XA_PRIMARY)
2229         {
2230                 plog("Paste failure (remote client did not send primary selection).");
2231                 return;
2232         }
2233
2234         if (ptr->target != request_target)
2235         {
2236                 plog("Paste failure (selection in unknown format).");
2237                 return;
2238         }
2239
2240         /* Get text */
2241         if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
2242                                length, TRUE, request_target,
2243                                &xtextproperty.encoding,
2244                                &xtextproperty.format,
2245                                &xtextproperty.nitems,
2246                                &left,
2247                                &xtextproperty.value)
2248             != Success)
2249         {
2250                 /* Failure */
2251                 return;
2252         }
2253
2254         if (request_target == xa_compound_text)
2255         {
2256                 char **list;
2257                 int count;
2258                 
2259                 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
2260
2261                 if (list)
2262                 {
2263                         int i;
2264
2265                         for (i = 0; i < count; i++)
2266                         {
2267                                 /* Paste the text. */
2268                                 err = type_string(list[i], 0);
2269
2270                                 if (err) break;
2271                         }
2272
2273                         /* Free the string */
2274                         XFreeStringList(list);
2275                 }
2276         }
2277         else /* if (request_target == XA_STRING) */
2278         {
2279                 /* Paste the text. */
2280                 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
2281         }
2282
2283         /* Free the data pasted. */
2284         XFree(xtextproperty.value); 
2285
2286         /* No room. */
2287         if (err)
2288         {
2289                 plog("Paste failure (too much text selected).");
2290         }
2291 }
2292
2293
2294 /*
2295  * Add a character to a string in preparation for sending it to another
2296  * client as a STRING.
2297  * This doesn't change anything, as clients tend not to have difficulty in
2298  * receiving this format (although the standard specifies a restricted set).
2299  * Strings do not have a colour.
2300  */
2301 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
2302 {
2303         char buf[1024];
2304         char *list[1000];
2305         co_ord max, min;
2306         TERM_LEN x,y;
2307         int l,n;
2308         TERM_COLOR a;
2309         char c;
2310
2311         /* Too old, or incorrect call. */
2312         if (rq->time < s_ptr->time) return FALSE;
2313
2314         /* Work out which way around to paste. */
2315         sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2316
2317         /* Paranoia. */
2318         if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
2319         {
2320                 /* bell("Someone stole my selection!"); */
2321                 return FALSE;
2322         }
2323
2324         /* Delete the old value of the property. */
2325         XDeleteProperty(DPY, rq->requestor, rq->property);
2326
2327         for (n = 0, y = 0; y < Term->hgt; y++)
2328         {
2329 #ifdef JP
2330                 int kanji = 0;
2331 #endif
2332                 if (y < min.y) continue;
2333                 if (y > max.y) break;
2334
2335                 for (l = 0, x = 0; x < Term->wid; x++)
2336                 {
2337 #ifdef JP
2338                         if (x > max.x) break;
2339
2340                         /* Find the character. */
2341                         Term_what(x, y, &a, &c);
2342
2343                         if (1 == kanji) kanji = 2;
2344                         else if (iskanji(c)) kanji = 1;
2345                         else kanji = 0;
2346
2347                         if (x < min.x) continue;
2348
2349                         /*
2350                          * A single kanji character was divided in two...
2351                          * Delete the garbage.
2352                          */
2353                         if ((2 == kanji && x == min.x) ||
2354                             (1 == kanji && x == max.x))
2355                                 c = ' ';
2356 #else
2357                         if (x > max.x) break;
2358                         if (x < min.x) continue;
2359
2360                         /* Find the character. */
2361                         Term_what(x, y, &a, &c);
2362 #endif
2363
2364                         /* Add it. */
2365                         buf[l] = c;
2366                         l++;
2367                 }
2368
2369                 /* Ignore trailing spaces */
2370                 while (buf[l-1] == ' ') l--;
2371
2372                 /* Terminate all line unless it's single line. */
2373                 if (min.y != max.y)
2374                 {
2375                         buf[l] = '\n';
2376                         l++;
2377                 }
2378
2379                 /* End of string */
2380                 buf[l] = '\0';
2381
2382                 list[n++] = (char *)string_make(buf);
2383         }
2384
2385         /* End of the list */
2386         list[n] = NULL;
2387
2388
2389         if (rq->target == XA_STRING)
2390         {
2391                 for (n = 0; list[n]; n++)
2392                 {
2393                         /* Send the (non-empty) string. */
2394                         XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
2395                                         PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
2396                 }
2397         }
2398
2399         else if (rq->target == xa_text || 
2400                  rq->target == xa_compound_text)
2401         {
2402                 XTextProperty text_prop;
2403                 XICCEncodingStyle style;
2404
2405                 if (rq->target == xa_text)
2406                         style = XStdICCTextStyle;
2407                 else /* if (rq->target == xa_compound_text) */
2408                         style = XCompoundTextStyle;
2409
2410                 if (Success ==
2411                     XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
2412                 {
2413                         /* Send the compound text */
2414                         XChangeProperty(DPY,
2415                                         rq->requestor,
2416                                         rq->property,
2417                                         text_prop.encoding,
2418                                         text_prop.format,
2419                                         PropModeAppend,
2420                                         text_prop.value,
2421                                         text_prop.nitems);
2422                                 
2423                         /* Free the data. */
2424                         XFree(text_prop.value);
2425                 }
2426         }
2427
2428         /* Free the list of strings */
2429         for (n = 0; list[n]; n++)
2430         {
2431                 string_free(list[n]);
2432         }
2433
2434         return TRUE;
2435 }
2436
2437 /*
2438  * Send some text requested by another X client.
2439  */
2440 static void paste_x11_send(XSelectionRequestEvent *rq)
2441 {
2442         XEvent event;
2443         XSelectionEvent *ptr = &(event.xselection);
2444
2445         /* Set the event parameters. */
2446         ptr->type = SelectionNotify;
2447         ptr->property = rq->property;
2448         ptr->display = rq->display;
2449         ptr->requestor = rq->requestor;
2450         ptr->selection = rq->selection;
2451         ptr->target = rq->target;
2452         ptr->time = rq->time;
2453
2454         /* Paste the appropriate information for each target type.
2455          * Note that this currently rejects MULTIPLE targets.
2456          */
2457
2458         if (rq->target == XA_STRING ||
2459             rq->target == xa_text ||
2460             rq->target == xa_compound_text)
2461         {
2462                 if (!paste_x11_send_text(rq))
2463                         ptr->property = None;
2464         }
2465         else if (rq->target == xa_targets)
2466         {
2467                 Atom target_list[4];
2468                 target_list[0] = XA_STRING;
2469                 target_list[1] = xa_text;
2470                 target_list[2] = xa_compound_text;
2471                 target_list[3] = xa_targets;
2472                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2473                         (8 * sizeof(target_list[0])), PropModeReplace,
2474                         (unsigned char *)target_list,
2475                         (sizeof(target_list) / sizeof(target_list[0])));
2476         }
2477         else if (rq->target == xa_timestamp)
2478         {
2479                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2480                         (8 * sizeof(Time)), PropModeReplace,
2481                         (unsigned char *)s_ptr->time, 1);
2482         }
2483         else
2484         {
2485                 ptr->property = None;
2486         }
2487
2488         /* Send whatever event we're left with. */
2489         XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
2490 }
2491
2492
2493 /*
2494  * Handle various events conditional on presses of a mouse button.
2495  */
2496 static void handle_button(Time time, int x, int y, int button,
2497         bool press)
2498 {
2499         /* The co-ordinates are only used in Angband format. */
2500         pixel_to_square(&x, &y, x, y);
2501
2502         if (press && button == 1) copy_x11_start(x, y);
2503         if (!press && button == 1) copy_x11_end(time);
2504         if (!press && button == 2) paste_x11_request(xa_compound_text, time);
2505 }
2506
2507
2508 /*
2509  * Process events
2510  */
2511 static errr CheckEvent(bool wait)
2512 {
2513         term_data *old_td = (term_data*)(Term->data);
2514
2515         XEvent xev_body, *xev = &xev_body;
2516
2517         term_data *td = NULL;
2518         infowin *iwin = NULL;
2519
2520         int i;
2521
2522 #ifdef USE_XIM
2523  redo_checkevent:
2524 #endif
2525
2526         /* Do not wait unless requested */
2527         if (!wait && !XPending(Metadpy->dpy)) return (1);
2528
2529         /*
2530          * Hack - redraw the selection, if needed.
2531          * This doesn't actually check that one of its squares was drawn to,
2532          * only that this may have happened.
2533          */
2534         if (s_ptr->select && !s_ptr->drawn) mark_selection();
2535
2536         /* Load the Event */
2537         XNextEvent(Metadpy->dpy, xev);
2538
2539 #ifdef USE_XIM
2540 /* #define DEBUG_EVENT */
2541 #ifdef DEBUG_EVENT
2542         {
2543                 printf("event: type=%d", xev->type);
2544                 switch(xev->type){
2545                 case KeyPress:
2546                         printf("(KeyPress), keycode=%X", xev->xkey.keycode);
2547                         break;
2548                 case FocusIn:
2549                         printf("(FocusIn)");
2550                         break;
2551                 case FocusOut:
2552                         printf("(FocusOut)");
2553                         break;
2554                 case ReparentNotify:
2555                         printf("(ReparentNotify)");
2556                         break;
2557                 case ConfigureNotify:
2558                         printf("(ConfigureNotify)");
2559                         break;
2560                 case MapNotify:
2561                         printf("(MapNotify)");
2562                         break;
2563                 case Expose:
2564                         printf("(Expose)");
2565                         break;
2566                 case ClientMessage:
2567                         printf("(ClientMessage)");
2568                         break;
2569                 }
2570                         
2571         }
2572 #endif
2573         if (XFilterEvent(xev, xev->xany.window)
2574                 /*XFilterEvent(xev, (data[0].win)->win)*/){
2575 #ifdef DEBUG_EVENT
2576                 printf(", [filtered by IM]\n");
2577 #endif
2578                 goto redo_checkevent;
2579         }
2580 #ifdef DEBUG_EVENT
2581         printf("\n");
2582 #endif
2583 #endif
2584
2585         /* Notice new keymaps */
2586         if (xev->type == MappingNotify)
2587         {
2588                 XRefreshKeyboardMapping(&xev->xmapping);
2589                 return 0;
2590         }
2591
2592
2593         /* Scan the windows */
2594         for (i = 0; i < MAX_TERM_DATA; i++)
2595         {
2596                 if (!data[i].win) continue;
2597                 if (xev->xany.window == data[i].win->win)
2598                 {
2599                         td = &data[i];
2600                         iwin = td->win;
2601                         break;
2602                 }
2603         }
2604
2605         /* Unknown window */
2606         if (!td || !iwin) return (0);
2607
2608
2609         /* Hack -- activate the Term */
2610         Term_activate(&td->t);
2611
2612         /* Hack -- activate the window */
2613         Infowin_set(iwin);
2614
2615
2616         /* Switch on the Type */
2617         switch (xev->type)
2618         {
2619                 case ButtonPress:
2620                 case ButtonRelease:
2621                 {
2622                         bool press = (xev->type == ButtonPress);
2623
2624                         /* Where is the mouse */
2625                         int x = xev->xbutton.x;
2626                         int y = xev->xbutton.y;
2627
2628                         int z;
2629
2630                         /* Which button is involved */
2631                         if (xev->xbutton.button == Button1) z = 1;
2632                         else if (xev->xbutton.button == Button2) z = 2;
2633                         else if (xev->xbutton.button == Button3) z = 3;
2634                         else if (xev->xbutton.button == Button4) z = 4;
2635                         else if (xev->xbutton.button == Button5) z = 5;
2636                         else z = 0;
2637
2638                         /* XXX Handle */
2639                         handle_button(xev->xbutton.time, x, y, z, press);
2640
2641                         break;
2642                 }
2643
2644                 case EnterNotify:
2645                 case LeaveNotify:
2646                 {
2647                         /* XXX Handle */
2648
2649                         break;
2650                 }
2651
2652                 case MotionNotify:
2653                 {
2654                         /* Where is the mouse */
2655                         int x = xev->xmotion.x;
2656                         int y = xev->xmotion.y;
2657                         unsigned int z = xev->xmotion.state;
2658
2659                         /* Convert to co-ordinates Angband understands. */
2660                         pixel_to_square(&x, &y, x, y);
2661
2662                         /* Highlight the current square, if appropriate. */
2663                         /* highlight_square(window, y, x); */
2664
2665                         /* Alter the selection if appropriate. */
2666                         copy_x11_cont(x, y, z);
2667
2668                         /* XXX Handle */
2669
2670                         break;
2671                 }
2672
2673                 case SelectionNotify:
2674                 {
2675                         paste_x11_accept(&(xev->xselection));
2676                         break;
2677                 }
2678
2679                 case SelectionRequest:
2680                 {
2681                         paste_x11_send(&(xev->xselectionrequest));
2682                         break;
2683                 }
2684
2685                 case SelectionClear:
2686                 {
2687                         s_ptr->select = FALSE;
2688                         mark_selection();
2689                         break;
2690                 }
2691
2692                 case KeyRelease:
2693                 {
2694                         /* Nothing */
2695                         break;
2696                 }
2697
2698                 case KeyPress:
2699                 {
2700                         /* Hack -- use "old" term */
2701                         Term_activate(&old_td->t);
2702
2703                         /* Process the key */
2704                         react_keypress(&(xev->xkey));
2705
2706                         break;
2707                 }
2708
2709                 case Expose:
2710                 {
2711                         int x1, x2, y1, y2;
2712                         
2713                         /* Ignore "extra" exposes */
2714                         /*if (xev->xexpose.count) break;*/
2715
2716                         /* Clear the window */
2717                         /*Infowin_wipe();*/
2718                         
2719                         x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
2720                         x2 = (xev->xexpose.x + xev->xexpose.width -
2721                                  Infowin->ox)/Infofnt->wid;
2722                         
2723                         y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
2724                         y2 = (xev->xexpose.y + xev->xexpose.height -
2725                                  Infowin->oy)/Infofnt->hgt;
2726                         
2727                         Term_redraw_section(x1, y1, x2, y2);
2728
2729                         /* Redraw */
2730                         /*Term_redraw();*/
2731
2732                         break;
2733                 }
2734
2735                 case MapNotify:
2736                 {
2737                         Infowin->mapped = 1;
2738                         Term->mapped_flag = TRUE;
2739                         break;
2740                 }
2741
2742                 case UnmapNotify:
2743                 {
2744                         Infowin->mapped = 0;
2745                         Term->mapped_flag = FALSE;
2746                         break;
2747                 }
2748
2749                 /* Move and/or Resize */
2750                 case ConfigureNotify:
2751                 {
2752                         int cols, rows, wid, hgt;
2753
2754                         int ox = Infowin->ox;
2755                         int oy = Infowin->oy;
2756
2757                         /* Save the new Window Parms */
2758                         Infowin->x = xev->xconfigure.x;
2759                         Infowin->y = xev->xconfigure.y;
2760                         Infowin->w = xev->xconfigure.width;
2761                         Infowin->h = xev->xconfigure.height;
2762
2763                         /* Determine "proper" number of rows/cols */
2764                         cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2765                         rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2766
2767                         /* Hack -- minimal size */
2768                         if (cols < 1) cols = 1;
2769                         if (rows < 1) rows = 1;
2770
2771                         if (td == &data[0])
2772                         {
2773                                 /* Hack the main window must be at least 80x24 */
2774                                 if (cols < 80) cols = 80;
2775                                 if (rows < 24) rows = 24;
2776                         }
2777
2778                         /* Desired size of window */
2779                         wid = cols * td->fnt->wid + (ox + ox);
2780                         hgt = rows * td->fnt->hgt + (oy + oy);
2781
2782                         /* Resize the Term (if needed) */
2783                         Term_resize(cols, rows);
2784
2785                         /* Resize the windows if any "change" is needed */
2786                         if ((Infowin->w != wid) || (Infowin->h != hgt))
2787                         {
2788                                 /* Resize window */
2789                                 Infowin_set(td->win);
2790                                 Infowin_resize(wid, hgt);
2791                         }
2792
2793                         break;
2794                 }
2795 #ifdef USE_XIM
2796                 case FocusIn:
2797                 {
2798                         if(iwin->xic){
2799                                 XSetICFocus(iwin->xic);
2800                         }
2801                         Focuswin = iwin;
2802                         break;
2803                 }
2804                 case FocusOut:
2805                 {
2806                         if(iwin->xic){
2807                                 XUnsetICFocus(iwin->xic);
2808                         }
2809                         /* Focuswin = NULL;*/
2810                         break;
2811                 }
2812 #endif
2813         }
2814
2815
2816         /* Hack -- Activate the old term */
2817         Term_activate(&old_td->t);
2818
2819         /* Hack -- Activate the proper window */
2820         Infowin_set(old_td->win);
2821
2822
2823         /* Success */
2824         return (0);
2825 }
2826
2827
2828 #ifdef USE_SOUND
2829
2830 /*
2831  * An array of sound file names
2832  */
2833 static concptr sound_file[SOUND_MAX];
2834
2835 /*
2836  * Check for existance of a file
2837  */
2838 static bool check_file(concptr s)
2839 {
2840         FILE *fff;
2841
2842         fff = fopen(s, "r");
2843         if (!fff) return (FALSE);
2844         
2845         fclose(fff);
2846         return (TRUE);
2847 }
2848
2849 /*
2850  * Initialize sound
2851  */
2852 static void init_sound(void)
2853 {
2854         int i;
2855         char wav[128];
2856         char buf[1024];
2857         char dir_xtra_sound[1024];
2858                 
2859         /* Build the "sound" path */
2860         path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
2861                 
2862         /* Prepare the sounds */
2863         for (i = 1; i < SOUND_MAX; i++)
2864         {
2865                 /* Extract name of sound file */
2866                 sprintf(wav, "%s.wav", angband_sound_name[i]);
2867                 
2868                 /* Access the sound */
2869                 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
2870                 
2871                 /* Save the sound filename, if it exists */
2872                 if (check_file(buf)) sound_file[i] = string_make(buf);
2873         }
2874         use_sound = TRUE;
2875         return;
2876 }
2877
2878 /*
2879  * Hack -- make a sound
2880  */
2881 static errr Term_xtra_x11_sound(int v)
2882 {
2883         char buf[1024];
2884         
2885         /* Sound disabled */
2886         if (!use_sound) return (1);
2887         
2888         /* Illegal sound */
2889         if ((v < 0) || (v >= SOUND_MAX)) return (1);
2890         
2891         /* Unknown sound */
2892         if (!sound_file[v]) return (1);
2893         
2894         sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
2895         
2896         return (system(buf) < 0);
2897         
2898 }
2899 #endif /* USE_SOUND */
2900
2901
2902 /*
2903  * Handle "activation" of a term
2904  */
2905 static errr Term_xtra_x11_level(int v)
2906 {
2907         term_data *td = (term_data*)(Term->data);
2908
2909         /* Handle "activate" */
2910         if (v)
2911         {
2912                 /* Activate the window */
2913                 Infowin_set(td->win);
2914
2915                 /* Activate the font */
2916                 Infofnt_set(td->fnt);
2917 #ifdef USE_JP_FONTSTRUCT
2918                 Infokfnt_set(td->kfnt);
2919 #endif
2920         }
2921
2922         /* Success */
2923         return (0);
2924 }
2925
2926
2927 /*
2928  * React to changes
2929  */
2930 static errr Term_xtra_x11_react(void)
2931 {
2932         int i;
2933         
2934         if (Metadpy->color)
2935         {
2936                 /* Check the colors */
2937                 for (i = 0; i < 256; i++)
2938                 {
2939                         if ((color_table[i][0] != angband_color_table[i][0]) ||
2940                             (color_table[i][1] != angband_color_table[i][1]) ||
2941                             (color_table[i][2] != angband_color_table[i][2]) ||
2942                             (color_table[i][3] != angband_color_table[i][3]))
2943                         {
2944                                 Pixell pixel;
2945
2946                                 /* Save new values */
2947                                 color_table[i][0] = angband_color_table[i][0];
2948                                 color_table[i][1] = angband_color_table[i][1];
2949                                 color_table[i][2] = angband_color_table[i][2];
2950                                 color_table[i][3] = angband_color_table[i][3];
2951
2952                                 /* Create pixel */
2953                                 pixel = create_pixel(Metadpy->dpy,
2954                                                      color_table[i][1],
2955                                                      color_table[i][2],
2956                                                      color_table[i][3]);
2957
2958                                 /* Change the foreground */
2959                                 Infoclr_set(clr[i]);
2960                                 Infoclr_change_fg(pixel);
2961                         }
2962                 }
2963         }
2964
2965         /* Success */
2966         return (0);
2967 }
2968
2969
2970 /*
2971  * Handle a "special request"
2972  */
2973 static errr Term_xtra_x11(int n, int v)
2974 {
2975         /* Handle a subset of the legal requests */
2976         switch (n)
2977         {
2978                 /* Make a noise */
2979                 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
2980
2981 #ifdef USE_SOUND
2982                 /* Make a special sound */
2983                 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
2984 #endif
2985
2986                 /* Flush the output XXX XXX */
2987                 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
2988
2989                 /* Process random events XXX */
2990                 case TERM_XTRA_BORED: return (CheckEvent(0));
2991
2992                 /* Process Events XXX */
2993                 case TERM_XTRA_EVENT: return (CheckEvent(v));
2994
2995                 /* Flush the events XXX */
2996                 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
2997
2998                 /* Handle change in the "level" */
2999                 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
3000
3001                 /* Clear the screen */
3002                 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
3003
3004                 /* Delay for some milliseconds */
3005                 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
3006
3007                 /* React to changes */
3008                 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
3009         }
3010
3011         /* Unknown */
3012         return (1);
3013 }
3014
3015
3016 /*
3017  * Draw the cursor as an inverted rectangle.
3018  *
3019  * Consider a rectangular outline like "main-mac.c".  XXX XXX
3020  */
3021 static errr Term_curs_x11(int x, int y)
3022 {
3023         if (use_graphics)
3024         {
3025                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3026                                x * Infofnt->wid + Infowin->ox,
3027                                y * Infofnt->hgt + Infowin->oy,
3028                                Infofnt->wid - 1, Infofnt->hgt - 1);
3029                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3030                                x * Infofnt->wid + Infowin->ox + 1,
3031                                y * Infofnt->hgt + Infowin->oy + 1,
3032                                Infofnt->wid - 3, Infofnt->hgt - 3);
3033         }
3034         else
3035         {
3036                 /* Draw the cursor */
3037                 Infoclr_set(xor);
3038
3039                 /* Hilite the cursor character */
3040                 Infofnt_text_non(x, y, " ", 1);
3041         }
3042
3043         /* Success */
3044         return (0);
3045 }
3046
3047
3048 /*
3049  * Draw the double width cursor
3050  */
3051 static errr Term_bigcurs_x11(int x, int y)
3052 {
3053         if (use_graphics)
3054         {
3055                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3056                                x * Infofnt->wid + Infowin->ox,
3057                                y * Infofnt->hgt + Infowin->oy,
3058                                Infofnt->twid - 1, Infofnt->hgt - 1);
3059                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3060                                x * Infofnt->wid + Infowin->ox + 1,
3061                                y * Infofnt->hgt + Infowin->oy + 1,
3062                                Infofnt->twid - 3, Infofnt->hgt - 3);
3063         }
3064         else
3065         {
3066                 /* Draw the cursor */
3067                 Infoclr_set(xor);
3068
3069                 /* Hilite the cursor character */
3070                 Infofnt_text_non(x, y, "  ", 2);
3071         }
3072         /* Success */
3073         return (0);
3074 }
3075
3076
3077 /*
3078  * Erase some characters.
3079  */
3080 static errr Term_wipe_x11(int x, int y, int n)
3081 {
3082         /* Erase (use black) */
3083         Infoclr_set(clr[TERM_DARK]);
3084
3085         /* Mega-Hack -- Erase some space */
3086         Infofnt_text_non(x, y, "", n);
3087
3088         /* Redraw the selection if any, as it may have been obscured. (later) */
3089         s_ptr->drawn = FALSE;
3090
3091         /* Success */
3092         return (0);
3093 }
3094
3095
3096 /*
3097  * Draw some textual characters.
3098  */
3099 static errr Term_text_x11(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
3100 {
3101         /* Draw the text */
3102         Infoclr_set(clr[a]);
3103
3104         /* Draw the text */
3105         Infofnt_text_std(x, y, s, n);
3106
3107         /* Redraw the selection if any, as it may have been obscured. (later) */
3108         s_ptr->drawn = FALSE;
3109
3110         /* Success */
3111         return (0);
3112 }
3113
3114
3115 #ifdef USE_GRAPHICS
3116
3117 /*
3118  * Draw some graphical characters.
3119  */
3120 static errr Term_pict_x11(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, const char *cp, const TERM_COLOR *tap, const char *tcp)
3121 {
3122         int i, x1, y1;
3123
3124         TERM_COLOR a;
3125         char c;
3126
3127         TERM_COLOR ta;
3128         char tc;
3129
3130         int x2, y2;
3131         int k,l;
3132
3133         unsigned long pixel, blank;
3134
3135         term_data *td = (term_data*)(Term->data);
3136
3137         y *= Infofnt->hgt;
3138         x *= Infofnt->wid;
3139
3140         /* Add in affect of window boundaries */
3141         y += Infowin->oy;
3142         x += Infowin->ox;
3143
3144         for (i = 0; i < n; ++i, x += td->fnt->wid)
3145         {
3146                 a = *ap++;
3147                 c = *cp++;
3148
3149                 /* For extra speed - cache these values */
3150                 x1 = (c&0x7F) * td->fnt->twid;
3151                 y1 = (a&0x7F) * td->fnt->hgt;
3152
3153                 /* Illegal tile index */
3154                 if (td->tiles->width < x1 + td->fnt->wid ||
3155                     td->tiles->height < y1 + td->fnt->hgt)
3156                 {
3157                         /* Draw black square */
3158                         XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc,
3159                                        x, y, 
3160                                        td->fnt->twid, td->fnt->hgt);
3161
3162                         /* Skip drawing tile */
3163                         continue;
3164                 }
3165
3166                 ta = *tap++;
3167                 tc = *tcp++;
3168
3169                 /* For extra speed - cache these values */
3170                 x2 = (tc&0x7F) * td->fnt->twid;
3171                 y2 = (ta&0x7F) * td->fnt->hgt;
3172                 
3173                 /* Optimise the common case */
3174                 if (((x1 == x2) && (y1 == y2)) ||
3175                     !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
3176                     td->tiles->width < x2 + td->fnt->wid ||
3177                     td->tiles->height < y2 + td->fnt->hgt)
3178                 {
3179                         /* Draw object / terrain */
3180                         XPutImage(Metadpy->dpy, td->win->win,
3181                                 clr[0]->gc,
3182                                 td->tiles,
3183                                 x1, y1,
3184                                 x, y,
3185                                 td->fnt->twid, td->fnt->hgt);   
3186                 }
3187                 else
3188                 {
3189
3190                         /* Mega Hack^2 - assume the top left corner is "black" */
3191                         blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
3192
3193                         for (k = 0; k < td->fnt->twid; k++)
3194                         {
3195                                 for (l = 0; l < td->fnt->hgt; l++)
3196                                 {
3197                                         /* If mask set... */
3198                                         if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
3199                                         {
3200                                                 /* Output from the terrain */
3201                                                 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
3202                                         }
3203                                         
3204                                         /* Store into the temp storage. */
3205                                         XPutPixel(td->TmpImage, k, l, pixel);
3206                                 }
3207                         }
3208
3209
3210                         /* Draw to screen */
3211
3212                         XPutImage(Metadpy->dpy, td->win->win,
3213                               clr[0]->gc,
3214                              td->TmpImage,
3215                              0, 0, x, y,
3216                              td->fnt->twid, td->fnt->hgt);
3217                 }
3218         }
3219
3220         /* Redraw the selection if any, as it may have been obscured. (later) */
3221         s_ptr->drawn = FALSE;
3222
3223         /* Success */
3224         return (0);
3225 }
3226
3227 #endif /* USE_GRAPHICS */
3228
3229 #ifdef USE_XIM
3230 static void IMDestroyCallback(XIM, XPointer, XPointer);
3231
3232 static void
3233 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
3234 {
3235         XIM xim;
3236         XIMCallback ximcallback;
3237         XIMStyles *xim_styles = NULL;
3238         int i;
3239
3240         /* Unused */
3241         (void)unused1;
3242         (void)unused2;
3243
3244         xim = XOpenIM(display, NULL, NULL, NULL);
3245         if(!xim){
3246                 printf("can't open IM\n");
3247                 return;
3248         }
3249
3250         /* initialize destroy callback */
3251         ximcallback.callback = IMDestroyCallback;
3252         ximcallback.client_data = NULL;
3253         XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
3254
3255         /* set style (only "Root" is supported yet...) */
3256         XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
3257         for (i = 0; i < xim_styles->count_styles; i++){
3258                 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
3259         }
3260         if(i >= xim_styles->count_styles){
3261                 printf("Sorry, your IM does not support 'Root' preedit style...\n");
3262                 XCloseIM(xim);
3263                 return;
3264         }
3265         XFree(xim_styles);
3266
3267         Metadpy->xim = xim;
3268
3269         for (i = 0; i < MAX_TERM_DATA; i++)
3270         {
3271                 infowin *iwin = data[i].win;
3272                 if (!iwin) continue;
3273                 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
3274                 if(!iwin->xic){
3275                         printf("Can't create input context for Term%d\n", i);
3276                         continue;
3277                 }
3278                 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL){
3279 /*                      printf("Can't get XNFilterEvents\n"); */
3280                         iwin->xic_mask = 0L;
3281                 }
3282                 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
3283         }
3284
3285         return;
3286 }
3287
3288 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
3289 {
3290         int i;
3291
3292         /* Unused */
3293         (void)xim;
3294         (void)client_data;
3295
3296         if (call_data == NULL){
3297                 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3298         }
3299
3300         for(i = 0; i < MAX_TERM_DATA; i++)
3301         {
3302                 infowin *iwin = data[i].win;
3303                 if(!iwin) continue;
3304                 if(iwin->xic_mask){
3305                         XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
3306                         iwin->xic_mask = 0L;
3307                 }
3308                 iwin->xic = NULL;
3309         }
3310
3311         Metadpy->xim = NULL;
3312 }
3313 #endif
3314
3315 /*
3316  * Initialize a term_data
3317  */
3318 static errr term_data_init(term_data *td, int i)
3319 {
3320         term *t = &td->t;
3321
3322         concptr name = angband_term_name[i];
3323
3324         concptr font;
3325 #ifdef USE_JP_FONTSTRUCT
3326         concptr kfont;
3327 #endif
3328
3329
3330         int x = 0;
3331         int y = 0;
3332
3333         int cols = 80;
3334         int rows = 24;
3335
3336         int ox = 1;
3337         int oy = 1;
3338
3339         int wid, hgt, num;
3340
3341         char buf[80];
3342
3343         concptr str;
3344
3345         int val;
3346
3347         XClassHint *ch;
3348
3349         char res_name[20];
3350         char res_class[20];
3351
3352         XSizeHints *sh;
3353 #ifdef USE_XIM
3354         XWMHints *wh;
3355 #endif
3356
3357         /* Window specific font name */
3358         sprintf(buf, "ANGBAND_X11_FONT_%d", i);
3359
3360         /* Check environment for that font */
3361         font = getenv(buf);
3362
3363         /* Check environment for "base" font */
3364         if (!font) font = getenv("ANGBAND_X11_FONT");
3365
3366         /* No environment variables, use default font */
3367         if (!font)
3368         {
3369                 switch (i)
3370                 {
3371                         case 0:
3372                         {
3373                                 font = DEFAULT_X11_FONT_0;
3374                         }
3375                         break;
3376                         case 1:
3377                         {
3378                                 font = DEFAULT_X11_FONT_1;
3379                         }
3380                         break;
3381                         case 2:
3382                         {
3383                                 font = DEFAULT_X11_FONT_2;
3384                         }
3385                         break;
3386                         case 3:
3387                         {
3388                                 font = DEFAULT_X11_FONT_3;
3389                         }
3390                         break;
3391                         case 4:
3392                         {
3393                                 font = DEFAULT_X11_FONT_4;
3394                         }
3395                         break;
3396                         case 5:
3397                         {
3398                                 font = DEFAULT_X11_FONT_5;
3399                         }
3400                         break;
3401                         case 6:
3402                         {
3403                                 font = DEFAULT_X11_FONT_6;
3404                         }
3405                         break;
3406                         case 7:
3407                         {
3408                                 font = DEFAULT_X11_FONT_7;
3409                         }
3410                         break;
3411                         default:
3412                         {
3413                                 font = DEFAULT_X11_FONT;
3414                         }
3415                 }
3416         }
3417
3418 #ifdef USE_JP_FONTSTRUCT
3419         /* Window specific font name */
3420         sprintf(buf, "ANGBAND_X11_KFONT_%d", i);
3421
3422         /* Check environment for that font */
3423         kfont = getenv(buf);
3424
3425         /* Check environment for "base" font */
3426         if (!kfont) kfont = getenv("ANGBAND_X11_KFONT");
3427
3428         /* No environment variables, use default font */
3429         if (!kfont)
3430         {
3431                 switch (i)
3432                 {
3433                         case 0:
3434                         {
3435                                 kfont = DEFAULT_X11_KFONT_0;
3436                         }
3437                         break;
3438                         case 1:
3439                         {
3440                                 kfont = DEFAULT_X11_KFONT_1;
3441                         }
3442                         break;
3443                         case 2:
3444                         {
3445                                 kfont = DEFAULT_X11_KFONT_2;
3446                         }
3447                         break;
3448                         case 3:
3449                         {
3450                                 kfont = DEFAULT_X11_KFONT_3;
3451                         }
3452                         break;
3453                         case 4:
3454                         {
3455                                 kfont = DEFAULT_X11_KFONT_4;
3456                         }
3457                         break;
3458                         case 5:
3459                         {
3460                                 kfont = DEFAULT_X11_KFONT_5;
3461                         }
3462                         break;
3463                         case 6:
3464                         {
3465                                 kfont = DEFAULT_X11_KFONT_6;
3466                         }
3467                         break;
3468                         case 7:
3469                         {
3470                                 kfont = DEFAULT_X11_KFONT_7;
3471                         }
3472                         break;
3473                         default:
3474                         {
3475                                 kfont = DEFAULT_X11_KFONT;
3476                         }
3477                 }
3478         }
3479 #endif
3480         /* Window specific location (x) */
3481         sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
3482         str = getenv(buf);
3483         x = (str != NULL) ? atoi(str) : -1;
3484
3485         /* Window specific location (y) */
3486         sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
3487         str = getenv(buf);
3488         y = (str != NULL) ? atoi(str) : -1;
3489
3490
3491         /* Window specific cols */
3492         sprintf(buf, "ANGBAND_X11_COLS_%d", i);
3493         str = getenv(buf);
3494         val = (str != NULL) ? atoi(str) : -1;
3495         if (val > 0) cols = val;
3496
3497         /* Window specific rows */
3498         sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
3499         str = getenv(buf);
3500         val = (str != NULL) ? atoi(str) : -1;
3501         if (val > 0) rows = val;
3502
3503         /* Hack the main window must be at least 80x24 */
3504         if (!i)
3505         {
3506                 if (cols < 80) cols = 80;
3507                 if (rows < 24) rows = 24;
3508         }
3509
3510         /* Window specific inner border offset (ox) */
3511         sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
3512         str = getenv(buf);
3513         val = (str != NULL) ? atoi(str) : -1;
3514         if (val > 0) ox = val;
3515
3516         /* Window specific inner border offset (oy) */
3517         sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
3518         str = getenv(buf);
3519         val = (str != NULL) ? atoi(str) : -1;
3520         if (val > 0) oy = val;
3521
3522
3523         /* Prepare the standard font */
3524 #ifdef USE_JP_FONTSTRUCT
3525         MAKE(td->fnt, infofnt);
3526         Infofnt_set(td->fnt);
3527         MAKE(td->kfnt, infofnt);
3528         Infokfnt_set(td->kfnt);
3529         Infofnt_init_data(font, kfont);
3530 #else
3531         MAKE(td->fnt, infofnt);
3532         Infofnt_set(td->fnt);
3533         Infofnt_init_data(font);
3534 #endif
3535
3536
3537         /* Hack -- key buffer size */
3538         num = ((i == 0) ? 1024 : 16);
3539
3540         /* Assume full size windows */
3541         wid = cols * td->fnt->wid + (ox + ox);
3542         hgt = rows * td->fnt->hgt + (oy + oy);
3543
3544         /* Create a top-window */
3545         MAKE(td->win, infowin);
3546         Infowin_set(td->win);
3547         Infowin_init_top(x, y, wid, hgt, 0,
3548                          Metadpy->fg, Metadpy->bg);
3549
3550         /* Ask for certain events */
3551 #if defined(USE_XIM)
3552         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
3553 #else
3554         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
3555 #endif
3556
3557         /* Set the window name */
3558         Infowin_set_name(name);
3559
3560         /* Save the inner border */
3561         Infowin->ox = ox;
3562         Infowin->oy = oy;
3563
3564         /* Make Class Hints */
3565         ch = XAllocClassHint();
3566
3567         if (ch == NULL) quit("XAllocClassHint failed");
3568
3569         strcpy(res_name, name);
3570         res_name[0] = FORCELOWER(res_name[0]);
3571         ch->res_name = res_name;
3572
3573         strcpy(res_class, "Angband");
3574         ch->res_class = res_class;
3575
3576         XSetClassHint(Metadpy->dpy, Infowin->win, ch);
3577
3578         /* Make Size Hints */
3579         sh = XAllocSizeHints();
3580
3581         /* Oops */
3582         if (sh == NULL) quit("XAllocSizeHints failed");
3583
3584         /* Main window has a differing minimum size */
3585         if (i == 0)
3586         {
3587                 /* Main window min size is 80x24 */
3588                 sh->flags = PMinSize | PMaxSize;
3589                 sh->min_width = 80 * td->fnt->wid + (ox + ox);
3590                 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
3591                 sh->max_width = 255 * td->fnt->wid + (ox + ox);
3592                 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
3593         }
3594
3595         /* Other windows can be shrunk to 1x1 */
3596         else
3597         {
3598                 /* Other windows */
3599                 sh->flags = PMinSize | PMaxSize;
3600                 sh->min_width = td->fnt->wid + (ox + ox);
3601                 sh->min_height = td->fnt->hgt + (oy + oy);
3602                 sh->max_width = 256 * td->fnt->wid + (ox + ox);
3603                 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
3604         }
3605
3606         /* Resize increment */
3607         sh->flags |= PResizeInc;
3608         sh->width_inc = td->fnt->wid;
3609         sh->height_inc = td->fnt->hgt;
3610
3611         /* Base window size */
3612         sh->flags |= PBaseSize;
3613         sh->base_width = (ox + ox);
3614         sh->base_height = (oy + oy);
3615
3616         /* Use the size hints */
3617         XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
3618
3619         /* Map the window */
3620         Infowin_map();
3621
3622 #ifdef USE_XIM
3623         /* Make WM Hints */
3624         wh = XAllocWMHints();
3625         if(wh == NULL) quit("XAllocWMHints failed");
3626         wh->flags = InputHint;
3627         wh->input = True;
3628         XSetWMHints(Metadpy->dpy, Infowin->win, wh);
3629 #endif
3630
3631         /* Move the window to requested location */
3632         if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
3633
3634
3635         /* Initialize the term */
3636         term_init(t, cols, rows, num);
3637
3638         /* Use a "soft" cursor */
3639         t->soft_cursor = TRUE;
3640
3641         /* Erase with "white space" */
3642         t->attr_blank = TERM_WHITE;
3643         t->char_blank = ' ';
3644
3645         /* Hooks */
3646         t->xtra_hook = Term_xtra_x11;
3647         t->curs_hook = Term_curs_x11;
3648         t->bigcurs_hook = Term_bigcurs_x11;
3649         t->wipe_hook = Term_wipe_x11;
3650         t->text_hook = Term_text_x11;
3651
3652         /* Save the data */
3653         t->data = td;
3654
3655         /* Activate (important) */
3656         Term_activate(t);
3657
3658         /* Success */
3659         return (0);
3660 }
3661
3662
3663 /*
3664  * Initialization function for an "X11" module to Angband
3665  */
3666 errr init_x11(int argc, char *argv[])
3667 {
3668         int i;
3669
3670         concptr dpy_name = "";
3671
3672         int num_term = 3;
3673
3674 #ifdef USE_GRAPHICS
3675
3676         char filename[1024];
3677
3678         int pict_wid = 0;
3679         int pict_hgt = 0;
3680
3681         char *TmpData;
3682 #endif /* USE_GRAPHICS */
3683
3684
3685         /* Parse args */
3686         for (i = 1; i < argc; i++)
3687         {
3688                 if (prefix(argv[i], "-d"))
3689                 {
3690                         dpy_name = &argv[i][2];
3691                         continue;
3692                 }
3693                 
3694 #ifdef USE_GRAPHICS
3695                 if (prefix(argv[i], "-s"))
3696                 {
3697                         smoothRescaling = FALSE;
3698                         continue;
3699                 }
3700
3701                 if (prefix(argv[i], "-a"))
3702                 {
3703                         arg_graphics = GRAPHICS_ADAM_BOLT;
3704                         continue;
3705                 }
3706
3707                 if (prefix(argv[i], "-o"))
3708                 {
3709                         arg_graphics = GRAPHICS_ORIGINAL;
3710                         continue;
3711                 }
3712
3713                 if (prefix(argv[i], "-b"))
3714                 {
3715                         arg_bigtile = use_bigtile = TRUE;
3716                         continue;
3717                 }
3718 #endif /* USE_GRAPHICS */
3719
3720                 if (prefix(argv[i], "-n"))
3721                 {
3722                         num_term = atoi(&argv[i][2]);
3723                         if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
3724                         else if (num_term < 1) num_term = 1;
3725                         continue;
3726                 }
3727
3728                 if (prefix(argv[i], "--"))
3729                 {
3730                         /* Ignore */
3731                         continue;
3732                 }
3733
3734                 plog_fmt("Ignoring option: %s", argv[i]);
3735         }
3736
3737 #ifdef USE_LOCALE
3738
3739 #ifdef JP
3740         /* Get locale information from environment variables */
3741         setlocale(LC_ALL, "");
3742
3743 #ifdef DEFAULT_LOCALE
3744         if(!strcmp(setlocale(LC_ALL, NULL), "C")){
3745                 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
3746                 setlocale(LC_ALL, DEFAULT_LOCALE);
3747         }
3748 #endif
3749
3750         if(!strcmp(setlocale(LC_ALL, NULL), "C"))
3751         {
3752                 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
3753         }
3754
3755         if(!XSupportsLocale()){
3756                 printf("can't support locale in X\n");
3757                 setlocale(LC_ALL, "C");
3758         }
3759 #else
3760         /* Set locale to "C" without using environment variables */
3761         setlocale(LC_ALL, "C");
3762 #endif /* JP */
3763
3764 #endif /* USE_LOCALE */
3765
3766
3767         /* Init the Metadpy if possible */
3768         if (Metadpy_init_name(dpy_name)) return (-1);
3769
3770
3771         /* Prepare cursor color */
3772         MAKE(xor, infoclr);
3773         Infoclr_set(xor);
3774         Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
3775
3776
3777         /* Prepare normal colors */
3778         for (i = 0; i < 256; ++i)
3779         {
3780                 Pixell pixel;
3781
3782                 MAKE(clr[i], infoclr);
3783
3784                 Infoclr_set(clr[i]);
3785
3786                 /* Acquire Angband colors */
3787                 color_table[i][0] = angband_color_table[i][0];
3788                 color_table[i][1] = angband_color_table[i][1];
3789                 color_table[i][2] = angband_color_table[i][2];
3790                 color_table[i][3] = angband_color_table[i][3];
3791
3792                 /* Default to monochrome */
3793                 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
3794
3795                 /* Handle color */
3796                 if (Metadpy->color)
3797                 {
3798                         /* Create pixel */
3799                         pixel = create_pixel(Metadpy->dpy,
3800                                              color_table[i][1],
3801                                              color_table[i][2],
3802                                              color_table[i][3]);
3803                 }
3804
3805                 /* Initialize the color */
3806                 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
3807         }
3808
3809
3810         /* Prepare required atoms. */
3811         set_atoms();
3812
3813
3814         /* Initialize the windows */
3815         for (i = 0; i < num_term; i++)
3816         {
3817                 term_data *td = &data[i];
3818
3819                 /* Initialize the term_data */
3820                 term_data_init(td, i);
3821
3822                 /* Save global entry */
3823                 angband_term[i] = Term;
3824         }
3825
3826         /* Raise the "Angband" window */
3827         Infowin_set(data[0].win);
3828         Infowin_raise();
3829
3830         /* Activate the "Angband" window screen */
3831         Term_activate(&data[0].t);
3832
3833 #ifdef USE_XIM
3834         {
3835                 char *p;
3836                 p = XSetLocaleModifiers("");
3837                 if(!p || !*p){
3838                         p = XSetLocaleModifiers("@im=");
3839                 }
3840 /*              printf("XMODIFIERS=\"%s\"\n", p); */
3841         }
3842         XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3843 #endif
3844
3845 #ifdef USE_SOUND
3846         /* initialize sound */
3847         if (arg_sound) init_sound();
3848 #endif
3849
3850 #ifdef USE_GRAPHICS
3851
3852         /* Try graphics */
3853         switch (arg_graphics)
3854         {
3855         case GRAPHICS_ORIGINAL:
3856                 /* Try the "8x8.bmp" file */
3857                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
3858
3859                 /* Use the "8x8.bmp" file if it exists */
3860                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3861                 {
3862                         /* Use graphics */
3863                         use_graphics = TRUE;
3864
3865                         pict_wid = pict_hgt = 8;
3866
3867                         ANGBAND_GRAF = "old";
3868                         break;
3869                 }
3870                 /* Fall through */
3871
3872         case GRAPHICS_ADAM_BOLT:
3873                 /* Try the "16x16.bmp" file */
3874                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
3875
3876                 /* Use the "16x16.bmp" file if it exists */
3877                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3878                 {
3879                         /* Use graphics */
3880                         use_graphics = TRUE;
3881
3882                         pict_wid = pict_hgt = 16;
3883
3884                         ANGBAND_GRAF = "new";
3885
3886                         break;
3887                 }
3888         }
3889
3890         /* Load graphics */
3891         if (use_graphics)
3892         {
3893                 Display *dpy = Metadpy->dpy;
3894
3895                 XImage *tiles_raw;
3896
3897                 /* Load the graphical tiles */
3898                 tiles_raw = ReadBMP(dpy, filename);
3899
3900                 /* Initialize the windows */
3901                 for (i = 0; i < num_term; i++)
3902                 {
3903                         term_data *td = &data[i];
3904
3905                         term *t = &td->t;
3906
3907                         /* Graphics hook */
3908                         t->pict_hook = Term_pict_x11;
3909
3910                         /* Use graphics sometimes */
3911                         t->higher_pict = TRUE;
3912
3913                         /* Resize tiles */
3914                         td->tiles =
3915                         ResizeImage(dpy, tiles_raw,
3916                                     pict_wid, pict_hgt,
3917                                     td->fnt->twid, td->fnt->hgt);
3918                 }
3919
3920                 /* Initialize the transparency masks */
3921                 for (i = 0; i < num_term; i++)
3922                 {
3923                         term_data *td = &data[i];
3924                         int ii, jj;
3925                         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
3926                         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
3927                         int total;
3928
3929
3930                         /* Determine total bytes needed for image */
3931                         ii = 1;
3932                         jj = (depth - 1) >> 2;
3933                         while (jj >>= 1) ii <<= 1;
3934                         total = td->fnt->twid * td->fnt->hgt * ii;
3935                         
3936                         
3937                         TmpData = (char *)malloc(total);
3938
3939                         td->TmpImage = XCreateImage(dpy,visual,depth,
3940                                 ZPixmap, 0, TmpData,
3941                                 td->fnt->twid, td->fnt->hgt, 8, 0);
3942
3943                 }
3944
3945                 /* Free tiles_raw? XXX XXX */
3946         }
3947
3948 #endif /* USE_GRAPHICS */
3949
3950
3951         /* Success */
3952         return (0);
3953 }
3954
3955 #endif /* USE_X11 */
3956