OSDN Git Service

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