OSDN Git Service

For clarity, reword English description of the SP_RUSH sniper ability.
[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 #include "system/angband.h"
96 #include "cmd-io/macro-util.h"
97 #include "game-option/runtime-arguments.h"
98 #include "game-option/special-options.h"
99 #include "io/files-util.h"
100 #include "main/sound-definitions-table.h"
101 #include "main/sound-of-music.h"
102 #include "main/x11-type-string.h"
103 #include "system/system-variables.h"
104 #include "term/gameterm.h"
105 #include "term/term-color-types.h"
106 #include "util/int-char-converter.h"
107 #include "util/angband-files.h"
108 #include "util/string-processor.h"
109
110 /*
111  * Available graphic modes
112  */
113 #define GRAPHICS_NONE       0
114 #define GRAPHICS_ORIGINAL   1
115 #define GRAPHICS_ADAM_BOLT  2
116 #define GRAPHICS_HENGBAND   3
117 #ifdef USE_X11
118 #ifndef __MAKEDEPEND__
119 #include <X11/Xlib.h>
120 #include <X11/Xutil.h>
121 #include <X11/keysym.h>
122 #include <X11/keysymdef.h>
123 #ifdef USE_LOCALE
124 #include <X11/Xlocale.h>
125 #endif
126 #include <X11/Xatom.h>
127 #endif /* __MAKEDEPEND__ */
128
129 #include <iconv.h>
130 #ifdef USE_XFT
131 #include <X11/Xft/Xft.h>
132 #endif
133
134 /*
135  * Include some helpful X11 code.
136  */
137 #include "maid-x11.c"
138
139
140 /*
141  * Notes on Colors:
142  *
143  *   1) On a monochrome (or "fake-monochrome") display, all colors
144  *   will be "cast" to "fg," except for the bg color, which is,
145  *   obviously, cast to "bg".  Thus, one can ignore this setting.
146  *
147  *   2) Because of the inner functioning of the color allocation
148  *   routines, colors may be specified as (a) a typical color name,
149  *   (b) a hexidecimal color specification (preceded by a pound sign),
150  *   or (c) by strings such as "fg", "bg", "zg".
151  *
152  *   3) Due to the workings of the init routines, many colors
153  *   may also be dealt with by their actual pixel values.  Note that
154  *   the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
155  *   is not necessarily either black or white.
156  */
157
158 /**** Generic Types ****/
159
160 /*
161  * An X11 pixell specifier
162  */
163 #ifdef USE_XFT
164 typedef XftColor Pixell;
165 #else
166 typedef unsigned long Pixell;
167 #endif
168
169 /*
170  * The structures defined below
171  */
172 typedef struct metadpy metadpy;
173 typedef struct infowin infowin;
174 typedef struct infoclr infoclr;
175 typedef struct infofnt infofnt;
176
177 /*
178  * A structure summarizing a given Display.
179  *
180  *      - The Display itself
181  *      - The default Screen for the display
182  *      - The virtual root (usually just the root)
183  *      - The default colormap (from a macro)
184  *
185  *      - The "name" of the display
186  *
187  *      - The socket to listen to for events
188  *
189  *      - The width of the display screen (from a macro)
190  *      - The height of the display screen (from a macro)
191  *      - The bit depth of the display screen (from a macro)
192  *
193  *      - The black Pixell (from a macro)
194  *      - The white Pixell (from a macro)
195  *
196  *      - The background Pixell (default: black)
197  *      - The foreground Pixell (default: white)
198  *      - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
199  *
200  *      - Bit Flag: Force all colors to black and white (default: !color)
201  *      - Bit Flag: Allow the use of color (default: depth > 1)
202  *      - Bit Flag: We created 'dpy', and so should nuke it when done.
203  */
204 struct metadpy
205 {
206         Display *dpy;
207         Screen *screen;
208         Window root;
209         Colormap cmap;
210 #ifdef USE_XIM
211         XIM xim;
212 #endif
213
214         char *name;
215
216         int fd;
217
218         uint width;
219         uint height;
220         uint depth;
221
222         Pixell black;
223         Pixell white;
224
225         Pixell bg;
226         Pixell fg;
227 #ifndef USE_XFT
228         Pixell zg;
229 #endif
230
231         uint mono:1;
232         uint color:1;
233         uint nuke:1;
234 };
235
236 /*
237  * A Structure summarizing Window Information.
238  *
239  * I assume that a window is at most 30000 pixels on a side.
240  * I assume that the root windw is also at most 30000 square.
241  *
242  *      - The Window
243  *      - The current Input Event Mask
244  *
245  *      - The location of the window
246  *      - The width, height of the window
247  *      - The border width of this window
248  *
249  *      - Byte: 1st Extra byte
250  *
251  *      - Bit Flag: This window is currently Mapped
252  *      - Bit Flag: This window needs to be redrawn
253  *      - Bit Flag: This window has been resized
254  *
255  *      - Bit Flag: We should nuke 'win' when done with it
256  *
257  *      - Bit Flag: 1st extra flag
258  *      - Bit Flag: 2nd extra flag
259  *      - Bit Flag: 3rd extra flag
260  *      - Bit Flag: 4th extra flag
261  */
262 struct infowin
263 {
264         Window win;
265 #ifdef USE_XIM
266         XIC xic;
267         long xic_mask;
268 #endif
269 #ifdef USE_XFT
270         XftDraw *draw;
271 #endif
272
273         long mask;
274
275         s16b ox, oy;
276
277         s16b x, y;
278         s16b w, h;
279         u16b b;
280
281         byte byte1;
282
283         uint mapped:1;
284         uint redraw:1;
285         uint resize:1;
286
287         uint nuke:1;
288
289         uint flag1:1;
290         uint flag2:1;
291         uint flag3:1;
292         uint flag4:1;
293 };
294
295 /*
296  * A Structure summarizing Operation+Color Information
297  *
298  *      - The actual GC corresponding to this info
299  *
300  *      - The Foreground Pixell Value
301  *      - The Background Pixell Value
302  *
303  *      - Num (0-15): The operation code (As in Clear, Xor, etc)
304  *      - Bit Flag: The GC is in stipple mode
305  *      - Bit Flag: Destroy 'gc' at Nuke time.
306  */
307 struct infoclr
308 {
309 #ifndef USE_XFT
310         GC gc;
311 #endif
312
313         Pixell fg;
314         Pixell bg;
315
316         uint code:4;
317         uint stip:1;
318         uint nuke:1;
319 };
320
321 /*
322  * A Structure to Hold Font Information
323  *
324  *      - The 'XFontStruct*' (yields the 'Font')
325  *
326  *      - The font name
327  *
328  *      - The default character width
329  *      - The default character height
330  *      - The default character ascent
331  *
332  *      - Byte: Pixel offset used during fake mono
333  *
334  *      - Flag: Force monospacing via 'wid'
335  *      - Flag: Nuke info when done
336  */
337 struct infofnt
338 {
339 #ifdef USE_XFT
340         XftFont *info;
341 #else
342         XFontSet info;
343 #endif
344         concptr name;
345
346         s16b wid;
347         s16b twid;
348         s16b hgt;
349         s16b asc;
350
351         byte off;
352
353         uint mono:1;
354         uint nuke:1;
355 };
356
357 /* Set current metadpy (Metadpy) to 'M' */
358 #define Metadpy_set(M) \
359         Metadpy = M
360
361 /* Initialize 'M' using Display 'D' */
362 #define Metadpy_init_dpy(D) \
363         Metadpy_init_2(D,cNULL)
364
365 /* Initialize 'M' using a Display named 'N' */
366 #define Metadpy_init_name(N) \
367         Metadpy_init_2((Display*)(NULL),N)
368
369 /* Initialize 'M' using the standard Display */
370 #define Metadpy_init() \
371         Metadpy_init_name("")
372
373 /* Init an infowin by giving father as an (info_win*) (or NULL), and data */
374 #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
375         Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
376                           X,Y,W,H,B,FG,BG)
377
378 /* Init a top level infowin by pos,size,bord,Colors */
379 #define Infowin_init_top(X,Y,W,H,B,FG,BG) \
380         Infowin_init_data(None,X,Y,W,H,B,FG,BG)
381
382 /* Request a new standard window by giving Dad infowin and X,Y,W,H */
383 #define Infowin_init_std(D,X,Y,W,H,B) \
384         Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
385
386 /* Set the current Infowin */
387 #define Infowin_set(I) \
388         (Infowin = (I))
389
390 /* Set the current Infoclr */
391 #define Infoclr_set(C) \
392         (Infoclr = (C))
393
394 #define Infoclr_init_ppo(F,B,O,M) \
395         Infoclr_init_data(F,B,O,M)
396
397 #define Infoclr_init_cco(F,B,O,M) \
398         Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
399
400 #define Infoclr_init_ppn(F,B,O,M) \
401         Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
402
403 #define Infoclr_init_ccn(F,B,O,M) \
404         Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
405
406 /* Set the current infofnt */
407 #define Infofnt_set(I) \
408         (Infofnt = (I))
409
410 /* Errr: Expose Infowin */
411 #define Infowin_expose() \
412         (!(Infowin->redraw = 1))
413
414 /* Errr: Unxpose Infowin */
415 #define Infowin_unexpose() \
416         (Infowin->redraw = 0)
417
418 /*
419  * The "default" values
420  */
421 static metadpy metadpy_default;
422
423 /*
424  * The "current" variables
425  */
426 static metadpy *Metadpy = &metadpy_default;
427 static infowin *Infowin = (infowin*)(NULL);
428 #ifdef USE_XIM
429 static infowin *Focuswin = (infowin*)(NULL);
430 #endif
431 static infoclr *Infoclr = (infoclr*)(NULL);
432 static infofnt *Infofnt = (infofnt*)(NULL);
433
434 /*
435  * Init the current metadpy, with various initialization stuff.
436  *
437  * Inputs:
438  *      dpy:  The Display* to use (if NULL, create it)
439  *      name: The name of the Display (if NULL, the current)
440  *
441  * Notes:
442  *      If 'name' is NULL, but 'dpy' is set, extract name from dpy
443  *      If 'dpy' is NULL, then Create the named Display
444  *      If 'name' is NULL, and so is 'dpy', use current Display
445  *
446  * Return -1 if no Display given, and none can be opened.
447  */
448 static errr Metadpy_init_2(Display *dpy, concptr name)
449 {
450         metadpy *m = Metadpy;
451         if (!dpy)
452         {
453                 dpy = XOpenDisplay(name);
454                 if (!dpy) return (-1);
455
456                 m->nuke = 1;
457         }
458         else
459         {
460                 m->nuke = 0;
461         }
462
463         m->dpy = dpy;
464         m->screen = DefaultScreenOfDisplay(dpy);
465         m->root = RootWindowOfScreen(m->screen);
466         m->cmap = DefaultColormapOfScreen(m->screen);
467         m->name = DisplayString(dpy);
468         m->fd = ConnectionNumber(Metadpy->dpy);
469         m->width = WidthOfScreen(m->screen);
470         m->height = HeightOfScreen(m->screen);
471         m->depth = DefaultDepthOfScreen(m->screen);
472
473 #ifdef USE_XFT
474         Visual *vis = DefaultVisual(dpy, 0);
475         XftColorAllocName(dpy, vis, m->cmap, "black", &m->black);
476         XftColorAllocName(dpy, vis, m->cmap, "white", &m->white);
477 #else
478         m->black = BlackPixelOfScreen(m->screen);
479         m->white = WhitePixelOfScreen(m->screen);
480 #endif
481
482         m->bg = m->black;
483         m->fg = m->white;
484
485 #ifndef USE_XFT
486         m->zg = (1 << m->depth) - 1;
487 #endif
488
489         m->color = ((m->depth > 1) ? 1 : 0);
490         m->mono = ((m->color) ? 0 : 1);
491         return (0);
492 }
493
494 /*
495  * General Flush/ Sync/ Discard routine
496  */
497 static errr Metadpy_update(int flush, int sync, int discard)
498 {
499         if (flush) XFlush(Metadpy->dpy);
500         if (sync) XSync(Metadpy->dpy, discard);
501
502         return (0);
503 }
504
505
506 /*
507  * Make a simple beep
508  */
509 static errr Metadpy_do_beep(void)
510 {
511         XBell(Metadpy->dpy, 100);
512         return (0);
513 }
514
515 /*
516  * Set the name (in the title bar) of Infowin
517  */
518 static errr Infowin_set_name(concptr name)
519 {
520         Status st;
521         XTextProperty tp;
522         char buf[128];
523         char *bp = buf;
524         strcpy(buf, name);
525         st = XStringListToTextProperty(&bp, 1, &tp);
526         if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
527         return (0);
528 }
529
530 /*
531  * Prepare a new 'infowin'.
532  */
533 static errr Infowin_prepare(Window xid)
534 {
535         infowin *iwin = Infowin;
536         Window tmp_win;
537         XWindowAttributes xwa;
538         int x, y;
539         unsigned int w, h, b, d;
540         iwin->win = xid;
541         XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
542
543 #ifdef USE_XFT
544         Visual *vis = DefaultVisual(Metadpy->dpy, 0);
545         if (vis->class != TrueColor) {
546                 quit_fmt("Display does not support truecolor.\n");
547         }
548         iwin->draw = XftDrawCreate(Metadpy->dpy, iwin->win, vis, Metadpy->cmap);
549 #endif
550
551         iwin->x = x;
552         iwin->y = y;
553         iwin->w = w;
554         iwin->h = h;
555         iwin->b = b;
556
557         XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
558         iwin->mask = xwa.your_event_mask;
559         iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
560         iwin->redraw = 1;
561         return (0);
562 }
563
564 /*
565  * Init an infowin by giving some data.
566  *
567  * Inputs:
568  *      dad: The Window that should own this Window (if any)
569  *      x,y: The position of this Window
570  *      w,h: The size of this Window
571  *      b,d: The border width and pixel depth
572  *
573  * Notes:
574  *      If 'dad == None' assume 'dad == root'
575  */
576 static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
577                               int b, Pixell fg, Pixell bg)
578 {
579         Window xid;
580         (void)WIPE(Infowin, infowin);
581         if (dad == None) dad = Metadpy->root;
582
583 #ifdef USE_XFT
584         xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg.pixel, bg.pixel);
585 #else
586         xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
587 #endif
588
589         XSelectInput(Metadpy->dpy, xid, 0L);
590         Infowin->nuke = 1;
591         return (Infowin_prepare(xid));
592 }
593
594 /*
595  * Modify the event mask of an Infowin
596  */
597 static errr Infowin_set_mask(long mask)
598 {
599         Infowin->mask = mask;
600         XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
601         return (0);
602 }
603
604 /*
605  * Request that Infowin be mapped
606  */
607 static errr Infowin_map(void)
608 {
609         XMapWindow(Metadpy->dpy, Infowin->win);
610         return (0);
611 }
612
613 /*
614  * Request that Infowin be raised
615  */
616 static errr Infowin_raise(void)
617 {
618         XRaiseWindow(Metadpy->dpy, Infowin->win);
619         return (0);
620 }
621
622 /*
623  * Request that Infowin be moved to a new location
624  */
625 static errr Infowin_impell(int x, int y)
626 {
627         XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
628         return (0);
629 }
630
631 /*
632  * Resize an infowin
633  */
634 static errr Infowin_resize(int w, int h)
635 {
636         XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
637         return (0);
638 }
639
640 /*
641  * Visually clear Infowin
642  */
643 static errr Infowin_wipe(void)
644 {
645         XClearWindow(Metadpy->dpy, Infowin->win);
646         return (0);
647 }
648
649 /*
650  * A NULL terminated pair list of legal "operation names"
651  *
652  * Pairs of values, first is texttual name, second is the string
653  * holding the decimal value that the operation corresponds to.
654  */
655 static concptr opcode_pairs[] =
656 {
657         "cpy", "3",
658         "xor", "6",
659         "and", "1",
660         "ior", "7",
661         "nor", "8",
662         "inv", "10",
663         "clr", "0",
664         "set", "15",
665
666         "src", "3",
667         "dst", "5",
668
669         "+andReverse", "2",
670         "+andInverted", "4",
671         "+noop", "5",
672         "+equiv", "9",
673         "+orReverse", "11",
674         "+copyInverted", "12",
675         "+orInverted", "13",
676         "+nand", "14",
677         NULL
678 };
679
680 /*
681  * Parse a word into an operation "code"
682  *
683  * Inputs:
684  *      str: A string, hopefully representing an Operation
685  *
686  * Output:
687  *      0-15: if 'str' is a valid Operation
688  *      -1:   if 'str' could not be parsed
689  */
690 static int Infoclr_Opcode(concptr str)
691 {
692         register int i;
693         for (i = 0; opcode_pairs[i*2]; ++i)
694         {
695                 if (streq(opcode_pairs[i*2], str))
696                 {
697                         return (atoi(opcode_pairs[i*2+1]));
698                 }
699         }
700
701         return (-1);
702 }
703
704 /*
705  * Initialize an infoclr with some data
706  *
707  * Inputs:
708  *      fg:   The Pixell for the requested Foreground (see above)
709  *      bg:   The Pixell for the requested Background (see above)
710  *      op:   The Opcode for the requested Operation (see above)
711  *      stip: The stipple mode
712  */
713 static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
714 {
715         infoclr *iclr = Infoclr;
716
717 #ifndef USE_XFT
718         GC gc;
719         XGCValues gcv;
720         unsigned long gc_mask;
721 #endif
722
723 #ifndef USE_XFT
724         if (bg > Metadpy->zg) return (-1);
725         if (fg > Metadpy->zg) return (-1);
726         if ((op < 0) || (op > 15)) return (-1);
727
728         gcv.function = op;
729         gcv.background = bg;
730         gcv.foreground = fg;
731         if (op == 6) gcv.background = 0;
732         if (op == 6) gcv.foreground = (bg ^ fg);
733
734         gcv.fill_style = (stip ? FillStippled : FillSolid);
735         gcv.graphics_exposures = False;
736         gc_mask = (GCFunction | GCBackground | GCForeground | GCFillStyle | GCGraphicsExposures);
737         gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
738 #endif
739
740         (void)WIPE(iclr, infoclr);
741
742 #ifndef USE_XFT
743         iclr->gc = gc;
744 #endif
745
746         iclr->nuke = 1;
747         iclr->fg = fg;
748         iclr->bg = bg;
749         iclr->code = op;
750         iclr->stip = stip ? 1 : 0;
751         return (0);
752 }
753
754 /*
755  * Change the 'fg' for an infoclr
756  *
757  * Inputs:
758  *      fg:   The Pixell for the requested Foreground (see above)
759  */
760 static errr Infoclr_change_fg(Pixell fg)
761 {
762         infoclr *iclr = Infoclr;
763
764 #ifdef USE_XFT
765         iclr->fg = fg;
766 #else
767         if (fg > Metadpy->zg) return (-1);
768
769         XSetForeground(Metadpy->dpy, iclr->gc, fg);
770 #endif
771
772         return (0);
773 }
774
775 /*
776  * Prepare a new 'infofnt'
777  */
778 #ifdef USE_XFT
779 static errr Infofnt_prepare(XftFont *info)
780 #else
781 static errr Infofnt_prepare(XFontSet info)
782 #endif
783 {
784         infofnt *ifnt = Infofnt;
785
786 #ifndef USE_XFT
787         XCharStruct *cs;
788         XFontStruct **fontinfo;
789         char **fontname;
790         int n_fonts;
791         int ascent, descent, width;
792 #endif
793
794         ifnt->info = info;
795
796
797 #ifdef USE_XFT
798         ifnt->asc = info->ascent;
799         ifnt->hgt = info->ascent + info->descent;
800         const char *text = "A";
801         XGlyphInfo extent;
802         XftTextExtentsUtf8(Metadpy->dpy, info, (FcChar8*)text, strlen(text), &extent);
803         ifnt->wid = extent.xOff;
804 #else
805         n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);
806
807         ascent = descent = width = 0;
808         while(n_fonts-- > 0){
809                 cs = &((*fontinfo)->max_bounds);
810                 if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
811                 if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
812                 if(((*fontinfo)->max_byte1) > 0){
813                         /* 多バイト文字の場合は幅半分(端数切り上げ)で評価する */
814                         if(width < (cs->width+1)/2) width = (cs->width+1)/2;
815                 }else{
816                         if(width < cs->width) width = cs->width;
817                 }
818                 fontinfo++;
819                 fontname++;
820         }
821         ifnt->asc = ascent;
822         ifnt->hgt = ascent + descent;
823         ifnt->wid = width;
824 #endif
825
826         if (use_bigtile)
827                 ifnt->twid = 2 * ifnt->wid;
828         else
829                 ifnt->twid = ifnt->wid;
830
831         return (0);
832 }
833
834 /*
835  * Init an infofnt by its Name
836  *
837  * Inputs:
838  *      name: The name of the requested Font
839  */
840 static void Infofnt_init_data(concptr name)
841
842 {
843 #ifdef USE_XFT
844         XftFont *info;
845 #else
846         XFontSet info;
847         char **missing_list;
848         int missing_count;
849         char *default_font;
850 #endif
851
852         if (!name || !*name) quit("Missing font!");
853
854 #ifdef USE_XFT
855         info = XftFontOpenName(Metadpy->dpy, 0, name);
856         /* TODO: error handling */
857 #else
858         info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
859         if(missing_count > 0){
860                 printf("missing font(s): \n");
861                 while(missing_count-- > 0){
862                         printf("\t%s\n", missing_list[missing_count]);
863                 }
864                 XFreeStringList(missing_list);
865         }
866 #endif
867
868         if (!info) quit_fmt("Failed to find font:\"%s\"", name);
869
870         (void)WIPE(Infofnt, infofnt);
871         if (Infofnt_prepare(info))
872         {
873 #ifdef USE_XFT
874                 XftFontClose(Metadpy->dpy, info);
875 #else
876                 XFreeFontSet(Metadpy->dpy, info);
877 #endif
878                 quit_fmt("Failed to prepare font:\"%s\"", name);
879         }
880
881         Infofnt->name = string_make(name);
882         Infofnt->nuke = 1;
883 }
884
885 /*
886  * Standard Text
887  */
888 static errr Infofnt_text_std(int x, int y, concptr str, int len)
889 {
890         if (!str || !*str) return (-1);
891
892         if (len < 0) len = strlen(str);
893
894         y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
895         x = (x * Infofnt->wid) + Infowin->ox;
896         if (Infofnt->mono)
897         {
898 #ifndef USE_XFT
899                 int i;
900                 for (i = 0; i < len; ++i)
901                 {
902                         XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc, x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
903                 }
904 #endif
905         }
906         else
907         {
908                 iconv_t cd = iconv_open("UTF-8", "EUC-JP");
909                 size_t inlen = len;
910                 size_t outlen = len * 2;
911                 char *kanji = malloc(outlen);
912                 char *sp; char *kp = kanji;
913                 char sbuf[1024];
914                 angband_strcpy(sbuf, str, sizeof(sbuf));
915                 sp = sbuf;
916                 iconv(cd, &sp, &inlen, &kp, &outlen);
917                 iconv_close(cd);
918
919 #ifdef USE_XFT
920                 XftDraw* draw = Infowin->draw;
921
922                 XRectangle r;
923                 r.x = 0;
924                 r.y = 0;
925                 r.width = Infofnt->wid*len;
926                 r.height = Infofnt->hgt;
927                 XftDrawSetClipRectangles(draw, x, y-Infofnt->asc, &r, 1);
928                 XftDrawRect(draw, &Infoclr->bg, x, y-Infofnt->asc, Infofnt->wid*len, Infofnt->hgt);
929                 XftDrawStringUtf8(draw, &Infoclr->fg, Infofnt->info, x, y,
930                          (FcChar8*)kanji, kp - kanji);
931                 XftDrawSetClip(draw, 0);
932 #else
933                 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
934                                 Infoclr->gc, x, y, kanji, kp-kanji);
935 #endif
936                 free(kanji);
937         }
938
939         return (0);
940 }
941
942 /*
943  * Painting where text would be
944  */
945 static errr Infofnt_text_non(int x, int y, concptr str, int len)
946 {
947         int w, h;
948         if (len < 0) len = strlen(str);
949
950         w = len * Infofnt->wid;
951         x = x * Infofnt->wid + Infowin->ox;
952         h = Infofnt->hgt;
953         y = y * h + Infowin->oy;
954
955 #ifdef USE_XFT
956         XftDrawRect(Infowin->draw, &Infoclr->fg, x, y, w, h);
957 #else
958         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
959 #endif
960
961         return (0);
962 }
963
964 /*
965  * Angband specific code follows... (ANGBAND)
966  */
967
968 /*
969  * Hack -- cursor color
970  */
971 static infoclr *xor;
972
973 /*
974  * Actual color table
975  */
976 static infoclr *clr[256];
977
978 /*
979  * Color info (unused, red, green, blue).
980  */
981 static byte color_table[256][4];
982
983 /*
984  * Forward declare
985  */
986 typedef struct term_data term_data;
987
988 /*
989  * A structure for each "term"
990  */
991 struct term_data
992 {
993         term_type t;
994         infofnt *fnt;
995         infowin *win;
996 #ifndef USE_XFT
997         XImage *tiles;
998         XImage *TmpImage;
999 #endif
1000 };
1001
1002 /*
1003  * The number of term data structures
1004  */
1005 #define MAX_TERM_DATA 8
1006
1007 /*
1008  * The array of term data structures
1009  */
1010 static term_data data[MAX_TERM_DATA];
1011
1012
1013 /* Use short names for the most commonly used elements of various structures. */
1014 #define DPY (Metadpy->dpy)
1015 #define WIN (Infowin->win)
1016
1017 /* Describe a set of co-ordinates. */
1018 typedef struct co_ord co_ord;
1019 struct co_ord
1020 {
1021         int x;
1022         int y;
1023 };
1024
1025 /*
1026  * A special structure to store information about the text currently
1027  * selected.
1028  */
1029 typedef struct x11_selection_type x11_selection_type;
1030 struct x11_selection_type
1031 {
1032         bool select; /* The selection is currently in use. */
1033         bool drawn; /* The selection is currently displayed. */
1034         term_type *t; /* The window where the selection is found. */
1035         co_ord init; /* The starting co-ordinates. */
1036         co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1037         co_ord old; /* The previous end co-ordinates. */
1038         Time time; /* The time at which the selection was finalised. */
1039 };
1040
1041 static x11_selection_type s_ptr[1];
1042
1043 /*
1044  * Convert to EUC-JP
1045  */
1046 #ifdef USE_XIM
1047 static void convert_to_euc(char *buf)
1048 {
1049         size_t inlen = strlen(buf);
1050         size_t outlen = inlen + 1;
1051         char tmp[outlen];
1052
1053         iconv_t iconvd = iconv_open("EUC-JP", "UTF-8");
1054         char *inbuf = buf;
1055         char *outbuf = tmp;
1056         iconv(iconvd, &inbuf, &inlen, &outbuf, &outlen);
1057         iconv_close(iconvd);
1058
1059         int i, l = strlen(tmp);
1060         for (i = 0; i < l; i++)
1061                 buf[i] = tmp[i];
1062         buf[l] = '\0';
1063 }
1064 #endif
1065
1066 // ゲーム側へキーを送る
1067 static void send_key(const char key)
1068 {
1069     // Windows ドライバと同様、自前でキューを操作する。
1070     // 逆順に term_key_push() する方法だと長い日本語を入力したときにテキストの
1071     // 順序が入れ替わってしまう。
1072
1073     // キーバッファが一杯なら入力を捨てる
1074     const int head_nxt = Term->key_head + 1 == Term->key_size ? 0 : Term->key_head + 1;
1075     if(head_nxt == Term->key_tail) {
1076         plog_fmt("key buffer overflow, ignoring key 0x%02X", key);
1077         return;
1078     }
1079
1080     Term->key_queue[Term->key_head] = key;
1081     Term->key_head = head_nxt;
1082 }
1083
1084 // ゲーム側へキー列を送る
1085 static void send_keys(const char* const keys)
1086 {
1087     for(const char* p = keys; *p != '\0'; ++p)
1088         send_key(*p);
1089 }
1090
1091 /*
1092  * Process a keypress event
1093  *
1094  * Also appears in "main-xaw.c".
1095  */
1096 static void react_keypress(XKeyEvent *xev)
1097 {
1098         int n, mc, ms, mo, mx;
1099         uint ks1;
1100         XKeyEvent *ev = (XKeyEvent*)(xev);
1101         KeySym ks;
1102         char buf[128];
1103         char msg[128];
1104
1105 #ifdef USE_XIM
1106         int valid_keysym = TRUE;
1107 #endif
1108
1109 #ifdef USE_XIM
1110         if(Focuswin && Focuswin->xic){
1111                 Status status;
1112                 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1113                 if(status == XBufferOverflow){
1114                         printf("Input is too long, and dropped\n");
1115                         return;
1116                 }
1117                 if(status != XLookupKeySym && status != XLookupBoth){
1118                         valid_keysym = FALSE;
1119                 }
1120         }else{
1121                 n = XLookupString(ev, buf, 125, &ks, NULL);
1122         }
1123 #else
1124         n = XLookupString(ev, buf, 125, &ks, NULL);
1125 #endif
1126
1127         buf[n] = '\0';
1128
1129 #ifdef USE_XIM
1130         if(!valid_keysym) { /* XIMからの入力時のみ FALSE になる */
1131                 convert_to_euc(buf);
1132                 send_keys(buf);
1133                 return;
1134         }
1135 #endif
1136
1137         if (IsModifierKey(ks)) return;
1138
1139         ks1 = (uint)(ks);
1140         mc = (ev->state & ControlMask) ? TRUE : FALSE;
1141         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1142         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1143         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1144         if (n && !mo && !mx && !IsSpecialKey(ks))
1145         {
1146                 send_keys(buf);
1147                 return;
1148         }
1149
1150         switch (ks1)
1151         {
1152                 case XK_Escape:
1153                 {
1154                         send_key(ESCAPE);
1155                         return;
1156                 }
1157
1158                 case XK_Return:
1159                 {
1160                         send_key('\r');
1161                         return;
1162                 }
1163
1164                 case XK_Tab:
1165                 {
1166                         send_key('\t');
1167                         return;
1168                 }
1169
1170                 case XK_Delete:
1171                 {
1172                         send_key(0x7f);
1173                         return;
1174                 }
1175                 case XK_BackSpace:
1176                 {
1177                         send_key('\010');
1178                         return;
1179                 }
1180         }
1181
1182         if (ks)
1183         {
1184                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1185                         mc ? "N" : "", ms ? "S" : "",
1186                         mo ? "O" : "", mx ? "M" : "",
1187                         (unsigned long)(ks), 13);
1188         }
1189         else
1190         {
1191                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1192                         mc ? "N" : "", ms ? "S" : "",
1193                         mo ? "O" : "", mx ? "M" : "",
1194                         ev->keycode, 13);
1195         }
1196
1197         send_keys(msg);
1198
1199         if (n && (macro_find_exact(msg) < 0))
1200         {
1201                 macro_add(msg, buf);
1202         }
1203 }
1204
1205 /*
1206  * Find the square a particular pixel is part of.
1207  */
1208 static void pixel_to_square(int * const x, int * const y,
1209         const int ox, const int oy)
1210 {
1211         (*x) = (ox - Infowin->ox) / Infofnt->wid;
1212         (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1213 }
1214
1215 /*
1216  * Find the pixel at the top-left corner of a square.
1217  */
1218 static void square_to_pixel(int * const x, int * const y,
1219         const int ox, const int oy)
1220 {
1221         (*x) = ox * Infofnt->wid + Infowin->ox;
1222         (*y) = oy * Infofnt->hgt + Infowin->oy;
1223 }
1224
1225 /*
1226  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
1227  */
1228 static void sort_co_ord(co_ord *min, co_ord *max,
1229         const co_ord *b, const co_ord *a)
1230 {
1231         min->x = MIN(a->x, b->x);
1232         min->y = MIN(a->y, b->y);
1233         max->x = MAX(a->x, b->x);
1234         max->y = MAX(a->y, b->y);
1235 }
1236
1237 /*
1238  * Remove the selection by redrawing it.
1239  */
1240 static void mark_selection_clear(int x1, int y1, int x2, int y2)
1241 {
1242         term_redraw_section(x1,y1,x2,y2);
1243 }
1244
1245 /*
1246  * Select an area by drawing a grey box around it.
1247  * NB. These two functions can cause flicker as the selection is modified,
1248  * as the game redraws the entire marked section.
1249  */
1250 static void mark_selection_mark(int x1, int y1, int x2, int y2)
1251 {
1252         square_to_pixel(&x1, &y1, x1, y1);
1253         square_to_pixel(&x2, &y2, x2, y2);
1254 #ifdef USE_XFT
1255         XftDrawRect(Infowin->draw, &clr[2]->fg, x1, y1, x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1256 #else
1257         XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
1258                 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1259 #endif
1260 }
1261
1262 /*
1263  * Mark a selection by drawing boxes around it (for now).
1264  */
1265 static void mark_selection(void)
1266 {
1267         co_ord min, max;
1268         term_type *old = Term;
1269         bool draw = s_ptr->select;
1270         bool clear = s_ptr->drawn;
1271         if (s_ptr->t != old) term_activate(s_ptr->t);
1272
1273         if (clear)
1274         {
1275                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
1276                 mark_selection_clear(min.x, min.y, max.x, max.y);
1277         }
1278         if (draw)
1279         {
1280                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1281                 mark_selection_mark(min.x, min.y, max.x, max.y);
1282         }
1283
1284         if (s_ptr->t != old) term_activate(old);
1285
1286         s_ptr->old.x = s_ptr->cur.x;
1287         s_ptr->old.y = s_ptr->cur.y;
1288         s_ptr->drawn = s_ptr->select;
1289 }
1290
1291 /*
1292  * Forget a selection for one reason or another.
1293  */
1294 static void copy_x11_release(void)
1295 {
1296         s_ptr->select = FALSE;
1297         mark_selection();
1298 }
1299
1300 /*
1301  * Start to select some text on the screen.
1302  */
1303 static void copy_x11_start(int x, int y)
1304 {
1305         if (s_ptr->select) copy_x11_release();
1306
1307         s_ptr->t = Term;
1308         s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
1309         s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
1310 }
1311
1312 /*
1313  * Respond to movement of the mouse when selecting text.
1314  */
1315 static void copy_x11_cont(int x, int y, unsigned int buttons)
1316 {
1317         x = MIN(MAX(x, 0), Term->wid-1);
1318         y = MIN(MAX(y, 0), Term->hgt-1);
1319         if (~buttons & Button1Mask) return;
1320         if (s_ptr->t != Term) return;
1321         if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
1322
1323         s_ptr->select = TRUE;
1324         s_ptr->cur.x = x;
1325         s_ptr->cur.y = y;
1326         mark_selection();
1327 }
1328
1329 /*
1330  * Respond to release of the left mouse button by putting the selected text in
1331  * the primary buffer.
1332  */
1333 static void copy_x11_end(const Time time)
1334 {
1335         if (!s_ptr->select) return;
1336         if (s_ptr->t != Term) return;
1337
1338         s_ptr->time = time;
1339         XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
1340         if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
1341         {
1342                 s_ptr->select = FALSE;
1343                 mark_selection();
1344         }
1345 }
1346
1347 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
1348
1349 /*
1350  * Set the required variable atoms at start-up to avoid errors later.
1351  */
1352 static void set_atoms(void)
1353 {
1354         xa_targets = XInternAtom(DPY, "TARGETS", False);
1355         xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
1356         xa_text = XInternAtom(DPY, "TEXT", False);
1357         xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
1358 }
1359
1360 static Atom request_target = 0;
1361
1362 /*
1363  * Send a message to request that the PRIMARY buffer be sent here.
1364  */
1365 static void paste_x11_request(Atom target, const Time time)
1366 {
1367         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1368         if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
1369         {
1370                 /* No selection. */
1371                 /* bell("No selection found."); */
1372                 return;
1373         }
1374
1375         request_target = target;
1376     XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
1377 }
1378
1379 /*
1380  * Add the contents of the PRIMARY buffer to the input queue.
1381  *
1382  * Hack - This doesn't use the "time" of the event, and so accepts anything a
1383  * client tries to send it.
1384  */
1385 static void paste_x11_accept(const XSelectionEvent *ptr)
1386 {
1387         unsigned long left;
1388         const long offset = 0;
1389         const long length = 32000;
1390         XTextProperty xtextproperty;
1391         errr err = 0;
1392         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1393         if (ptr->property == None)
1394         {
1395                 if (request_target == xa_compound_text)
1396                 {
1397                         paste_x11_request(XA_STRING, ptr->time);
1398                 }
1399                 else
1400                 {
1401                         request_target = 0;
1402                         plog("Paste failure (remote client could not send).");
1403                 }
1404
1405                 return;
1406         }
1407
1408         if (ptr->selection != XA_PRIMARY)
1409         {
1410                 plog("Paste failure (remote client did not send primary selection).");
1411                 return;
1412         }
1413
1414         if (ptr->target != request_target)
1415         {
1416                 plog("Paste failure (selection in unknown format).");
1417                 return;
1418         }
1419
1420         if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
1421                                length, TRUE, request_target,
1422                                &xtextproperty.encoding,
1423                                &xtextproperty.format,
1424                                &xtextproperty.nitems,
1425                                &left,
1426                                &xtextproperty.value)
1427             != Success)
1428         {
1429                 return;
1430         }
1431
1432         if (request_target == xa_compound_text)
1433         {
1434                 char **list;
1435                 int count;
1436                 
1437                 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
1438
1439                 if (list)
1440                 {
1441                         int i;
1442
1443                         for (i = 0; i < count; i++)
1444                         {
1445                                 err = type_string(list[i], 0);
1446                                 if (err) break;
1447                         }
1448
1449                         XFreeStringList(list);
1450                 }
1451         }
1452         else
1453         {
1454                 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
1455         }
1456
1457         XFree(xtextproperty.value); 
1458         if (err)
1459         {
1460                 plog("Paste failure (too much text selected).");
1461         }
1462 }
1463
1464 /*
1465  * Add a character to a string in preparation for sending it to another
1466  * client as a STRING.
1467  * This doesn't change anything, as clients tend not to have difficulty in
1468  * receiving this format (although the standard specifies a restricted set).
1469  * Strings do not have a colour.
1470  */
1471 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
1472 {
1473         char buf[1024];
1474         char *list[1000];
1475         co_ord max, min;
1476         TERM_LEN x,y;
1477         int l,n;
1478         TERM_COLOR a;
1479         char c;
1480
1481         if (rq->time < s_ptr->time) return FALSE;
1482
1483         sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1484         if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
1485         {
1486                 return FALSE;
1487         }
1488
1489         XDeleteProperty(DPY, rq->requestor, rq->property);
1490
1491         for (n = 0, y = 0; y < Term->hgt; y++)
1492         {
1493 #ifdef JP
1494                 int kanji = 0;
1495 #endif
1496                 if (y < min.y) continue;
1497                 if (y > max.y) break;
1498
1499                 for (l = 0, x = 0; x < Term->wid; x++)
1500                 {
1501 #ifdef JP
1502                         if (x > max.x) break;
1503
1504                         term_what(x, y, &a, &c);
1505                         if (1 == kanji) kanji = 2;
1506                         else if (iskanji(c)) kanji = 1;
1507                         else kanji = 0;
1508
1509                         if (x < min.x) continue;
1510
1511                         /*
1512                          * A single kanji character was divided in two...
1513                          * Delete the garbage.
1514                          */
1515                         if ((2 == kanji && x == min.x) ||
1516                             (1 == kanji && x == max.x))
1517                                 c = ' ';
1518 #else
1519                         if (x > max.x) break;
1520                         if (x < min.x) continue;
1521
1522                         term_what(x, y, &a, &c);
1523 #endif
1524
1525                         buf[l] = c;
1526                         l++;
1527                 }
1528
1529                 while (buf[l-1] == ' ') l--;
1530
1531                 if (min.y != max.y)
1532                 {
1533                         buf[l] = '\n';
1534                         l++;
1535                 }
1536
1537                 buf[l] = '\0';
1538                 list[n++] = (char *)string_make(buf);
1539         }
1540
1541         list[n] = NULL;
1542         if (rq->target == XA_STRING)
1543         {
1544                 for (n = 0; list[n]; n++)
1545                 {
1546                         XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
1547                                         PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
1548                 }
1549         }
1550         else if (rq->target == xa_text || 
1551                  rq->target == xa_compound_text)
1552         {
1553                 XTextProperty text_prop;
1554                 XICCEncodingStyle style;
1555
1556                 if (rq->target == xa_text)
1557                         style = XStdICCTextStyle;
1558                 else
1559                         style = XCompoundTextStyle;
1560
1561                 if (Success ==
1562                     XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
1563                 {
1564                         XChangeProperty(DPY,
1565                                         rq->requestor,
1566                                         rq->property,
1567                                         text_prop.encoding,
1568                                         text_prop.format,
1569                                         PropModeAppend,
1570                                         text_prop.value,
1571                                         text_prop.nitems);
1572                         XFree(text_prop.value);
1573                 }
1574         }
1575
1576         for (n = 0; list[n]; n++)
1577         {
1578                 string_free(list[n]);
1579         }
1580
1581         return TRUE;
1582 }
1583
1584 /*
1585  * Send some text requested by another X client.
1586  */
1587 static void paste_x11_send(XSelectionRequestEvent *rq)
1588 {
1589         XEvent event;
1590         XSelectionEvent *ptr = &(event.xselection);
1591
1592         ptr->type = SelectionNotify;
1593         ptr->property = rq->property;
1594         ptr->display = rq->display;
1595         ptr->requestor = rq->requestor;
1596         ptr->selection = rq->selection;
1597         ptr->target = rq->target;
1598         ptr->time = rq->time;
1599
1600         /*
1601          * Paste the appropriate information for each target type.
1602          * Note that this currently rejects MULTIPLE targets.
1603          */
1604
1605         if (rq->target == XA_STRING ||
1606             rq->target == xa_text ||
1607             rq->target == xa_compound_text)
1608         {
1609                 if (!paste_x11_send_text(rq))
1610                         ptr->property = None;
1611         }
1612         else if (rq->target == xa_targets)
1613         {
1614                 Atom target_list[4];
1615                 target_list[0] = XA_STRING;
1616                 target_list[1] = xa_text;
1617                 target_list[2] = xa_compound_text;
1618                 target_list[3] = xa_targets;
1619                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1620                         (8 * sizeof(target_list[0])), PropModeReplace,
1621                         (unsigned char *)target_list,
1622                         (sizeof(target_list) / sizeof(target_list[0])));
1623         }
1624         else if (rq->target == xa_timestamp)
1625         {
1626                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1627                         (8 * sizeof(Time)), PropModeReplace,
1628                         (unsigned char *)s_ptr->time, 1);
1629         }
1630         else
1631         {
1632                 ptr->property = None;
1633         }
1634
1635         XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
1636 }
1637
1638 /*
1639  * Handle various events conditional on presses of a mouse button.
1640  */
1641 static void handle_button(Time time, int x, int y, int button, bool press)
1642 {
1643         pixel_to_square(&x, &y, x, y);
1644
1645         if (press && button == 1) copy_x11_start(x, y);
1646         if (!press && button == 1) copy_x11_end(time);
1647         if (!press && button == 2) paste_x11_request(xa_compound_text, time);
1648 }
1649
1650 /*
1651  * Process events
1652  */
1653 static errr CheckEvent(bool wait)
1654 {
1655         term_data *old_td = (term_data*)(Term->data);
1656
1657         XEvent xev_body, *xev = &xev_body;
1658
1659         term_data *td = NULL;
1660         infowin *iwin = NULL;
1661
1662         int i;
1663
1664 #ifdef USE_XIM
1665         do
1666         {
1667 #endif
1668
1669                 if (!wait && !XPending(Metadpy->dpy)) return (1);
1670
1671                 if (s_ptr->select && !s_ptr->drawn) mark_selection();
1672
1673                 XNextEvent(Metadpy->dpy, xev);
1674
1675 #ifdef USE_XIM
1676         } while (XFilterEvent(xev, xev->xany.window));
1677 #endif
1678
1679         if (xev->type == MappingNotify)
1680         {
1681                 XRefreshKeyboardMapping(&xev->xmapping);
1682                 return 0;
1683         }
1684
1685         for (i = 0; i < MAX_TERM_DATA; i++)
1686         {
1687                 if (!data[i].win) continue;
1688                 if (xev->xany.window == data[i].win->win)
1689                 {
1690                         td = &data[i];
1691                         iwin = td->win;
1692                         break;
1693                 }
1694         }
1695
1696         if (!td || !iwin) return (0);
1697
1698         term_activate(&td->t);
1699         Infowin_set(iwin);
1700         switch (xev->type)
1701         {
1702                 case ButtonPress:
1703                 case ButtonRelease:
1704                 {
1705                         bool press = (xev->type == ButtonPress);
1706                         int x = xev->xbutton.x;
1707                         int y = xev->xbutton.y;
1708                         int z;
1709                         if (xev->xbutton.button == Button1) z = 1;
1710                         else if (xev->xbutton.button == Button2) z = 2;
1711                         else if (xev->xbutton.button == Button3) z = 3;
1712                         else if (xev->xbutton.button == Button4) z = 4;
1713                         else if (xev->xbutton.button == Button5) z = 5;
1714                         else z = 0;
1715
1716                         handle_button(xev->xbutton.time, x, y, z, press);
1717                         break;
1718                 }
1719                 case EnterNotify:
1720                 case LeaveNotify:
1721                 {
1722                         break;
1723                 }
1724                 case MotionNotify:
1725                 {
1726                         int x = xev->xmotion.x;
1727                         int y = xev->xmotion.y;
1728                         unsigned int z = xev->xmotion.state;
1729                         pixel_to_square(&x, &y, x, y);
1730                         copy_x11_cont(x, y, z);
1731                         break;
1732                 }
1733                 case SelectionNotify:
1734                 {
1735                         paste_x11_accept(&(xev->xselection));
1736                         break;
1737                 }
1738                 case SelectionRequest:
1739                 {
1740                         paste_x11_send(&(xev->xselectionrequest));
1741                         break;
1742                 }
1743                 case SelectionClear:
1744                 {
1745                         s_ptr->select = FALSE;
1746                         mark_selection();
1747                         break;
1748                 }
1749                 case KeyRelease:
1750                 {
1751                         break;
1752                 }
1753                 case KeyPress:
1754                 {
1755                         term_activate(&old_td->t);
1756                         react_keypress(&(xev->xkey));
1757                         break;
1758                 }
1759                 case Expose:
1760                 {
1761                         int x1, x2, y1, y2;
1762                         x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
1763                         x2 = (xev->xexpose.x + xev->xexpose.width -
1764                                  Infowin->ox)/Infofnt->wid;
1765                         
1766                         y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
1767                         y2 = (xev->xexpose.y + xev->xexpose.height -
1768                                  Infowin->oy)/Infofnt->hgt;
1769                         
1770                         term_redraw_section(x1, y1, x2, y2);
1771                         break;
1772                 }
1773                 case MapNotify:
1774                 {
1775                         Infowin->mapped = 1;
1776                         Term->mapped_flag = TRUE;
1777                         break;
1778                 }
1779                 case UnmapNotify:
1780                 {
1781                         Infowin->mapped = 0;
1782                         Term->mapped_flag = FALSE;
1783                         break;
1784                 }
1785                 case ConfigureNotify:
1786                 {
1787                         int cols, rows, wid, hgt;
1788                         int ox = Infowin->ox;
1789                         int oy = Infowin->oy;
1790                         Infowin->x = xev->xconfigure.x;
1791                         Infowin->y = xev->xconfigure.y;
1792                         Infowin->w = xev->xconfigure.width;
1793                         Infowin->h = xev->xconfigure.height;
1794                         cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
1795                         rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
1796                         if (cols < 1) cols = 1;
1797                         if (rows < 1) rows = 1;
1798
1799                         if (td == &data[0])
1800                         {
1801                                 if (cols < 80) cols = 80;
1802                                 if (rows < 24) rows = 24;
1803                         }
1804
1805                         wid = cols * td->fnt->wid + (ox + ox);
1806                         hgt = rows * td->fnt->hgt + (oy + oy);
1807                         term_resize(cols, rows);
1808                         if ((Infowin->w != wid) || (Infowin->h != hgt))
1809                         {
1810                                 Infowin_set(td->win);
1811                                 Infowin_resize(wid, hgt);
1812                         }
1813
1814                         break;
1815                 }
1816 #ifdef USE_XIM
1817                 case FocusIn:
1818                 {
1819                         if(iwin->xic){
1820                                 XSetICFocus(iwin->xic);
1821                         }
1822                         Focuswin = iwin;
1823                         break;
1824                 }
1825                 case FocusOut:
1826                 {
1827                         if(iwin->xic)
1828                         {
1829                                 XUnsetICFocus(iwin->xic);
1830                         }
1831
1832                         break;
1833                 }
1834 #endif
1835         }
1836
1837         term_activate(&old_td->t);
1838         Infowin_set(old_td->win);
1839         return (0);
1840 }
1841
1842 /*
1843  * An array of sound file names
1844  */
1845 static concptr sound_file[SOUND_MAX];
1846
1847 /*
1848  * Check for existance of a file
1849  */
1850 static bool check_file(concptr s)
1851 {
1852         FILE *fff;
1853
1854         fff = fopen(s, "r");
1855         if (!fff) return (FALSE);
1856         
1857         fclose(fff);
1858         return (TRUE);
1859 }
1860
1861 /*
1862  * Initialize sound
1863  */
1864 static void init_sound(void)
1865 {
1866         int i;
1867         char wav[128];
1868         char buf[1024];
1869         char dir_xtra_sound[1024];
1870         path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
1871         for (i = 1; i < SOUND_MAX; i++)
1872         {
1873                 sprintf(wav, "%s.wav", angband_sound_name[i]);
1874                 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
1875                 if (check_file(buf)) sound_file[i] = string_make(buf);
1876         }
1877
1878         use_sound = TRUE;
1879         return;
1880 }
1881
1882 /*
1883  * Hack -- make a sound
1884  */
1885 static errr Term_xtra_x11_sound(int v)
1886 {
1887         char buf[1024];
1888         if (!use_sound) return (1);
1889         if ((v < 0) || (v >= SOUND_MAX)) return (1);
1890         if (!sound_file[v]) return (1);
1891         
1892         sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
1893         return (system(buf) < 0);
1894         
1895 }
1896
1897 /*
1898  * Handle "activation" of a term
1899  */
1900 static errr Term_xtra_x11_level(int v)
1901 {
1902         term_data *td = (term_data*)(Term->data);
1903         if (v)
1904         {
1905                 Infowin_set(td->win);
1906                 Infofnt_set(td->fnt);
1907         }
1908
1909         return (0);
1910 }
1911
1912 /*
1913  * React to changes
1914  */
1915 static errr Term_xtra_x11_react(void)
1916 {
1917         int i;
1918         
1919         if (Metadpy->color)
1920         {
1921                 for (i = 0; i < 256; i++)
1922                 {
1923                         if ((color_table[i][0] != angband_color_table[i][0]) ||
1924                             (color_table[i][1] != angband_color_table[i][1]) ||
1925                             (color_table[i][2] != angband_color_table[i][2]) ||
1926                             (color_table[i][3] != angband_color_table[i][3]))
1927                         {
1928                                 Pixell pixel;
1929                                 color_table[i][0] = angband_color_table[i][0];
1930                                 color_table[i][1] = angband_color_table[i][1];
1931                                 color_table[i][2] = angband_color_table[i][2];
1932                                 color_table[i][3] = angband_color_table[i][3];
1933                                 pixel = create_pixel(Metadpy->dpy,
1934                                                      color_table[i][1],
1935                                                      color_table[i][2],
1936                                                      color_table[i][3]);
1937                                 Infoclr_set(clr[i]);
1938                                 Infoclr_change_fg(pixel);
1939                         }
1940                 }
1941         }
1942
1943         return (0);
1944 }
1945
1946 /*
1947  * Handle a "special request"
1948  */
1949 static errr Term_xtra_x11(int n, int v)
1950 {
1951         switch (n)
1952         {
1953                 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
1954                 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
1955 #ifdef USE_XFT
1956                 case TERM_XTRA_FRESH: Metadpy_update(1, 1, 0); return (0);
1957 #else
1958                 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
1959 #endif
1960                 case TERM_XTRA_BORED: return (CheckEvent(0));
1961                 case TERM_XTRA_EVENT: return (CheckEvent(v));
1962                 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
1963                 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
1964                 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
1965                 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
1966                 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
1967         }
1968
1969         return (1);
1970 }
1971
1972 /*
1973  * Draw the cursor as an inverted rectangle.
1974  *
1975  * Consider a rectangular outline like "main-mac.c".  XXX XXX
1976  */
1977 static errr Term_curs_x11(int x, int y)
1978 {
1979         if (use_graphics)
1980         {
1981 #ifdef USE_XFT
1982                 XftDrawRect(Infowin->draw, &xor->fg,
1983                             x * Infofnt->wid + Infowin->ox,
1984                             y * Infofnt->hgt + Infowin->oy,
1985                             Infofnt->wid - 1, Infofnt->hgt - 1);
1986                 XftDrawRect(Infowin->draw, &xor->fg,
1987                             x * Infofnt->wid + Infowin->ox + 1,
1988                             y * Infofnt->hgt + Infowin->oy + 1,
1989                             Infofnt->wid - 3, Infofnt->hgt - 3);
1990 #else
1991                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
1992                                x * Infofnt->wid + Infowin->ox,
1993                                y * Infofnt->hgt + Infowin->oy,
1994                                Infofnt->wid - 1, Infofnt->hgt - 1);
1995                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
1996                                x * Infofnt->wid + Infowin->ox + 1,
1997                                y * Infofnt->hgt + Infowin->oy + 1,
1998                                Infofnt->wid - 3, Infofnt->hgt - 3);
1999 #endif
2000         }
2001         else
2002         {
2003                 Infoclr_set(xor);
2004                 Infofnt_text_non(x, y, " ", 1);
2005         }
2006
2007         return (0);
2008 }
2009
2010
2011 /*
2012  * Draw the double width cursor
2013  */
2014 static errr Term_bigcurs_x11(int x, int y)
2015 {
2016         if (use_graphics)
2017         {
2018 #ifdef USE_XFT
2019                 XftDrawRect(Infowin->draw, &xor->fg,
2020                             x * Infofnt->wid + Infowin->ox,
2021                             y * Infofnt->hgt + Infowin->oy,
2022                             Infofnt->twid - 1, Infofnt->hgt - 1);
2023                 XftDrawRect(Infowin->draw, &xor->fg,
2024                             x * Infofnt->wid + Infowin->ox + 1,
2025                             y * Infofnt->hgt + Infowin->oy + 1,
2026                             Infofnt->twid - 3, Infofnt->hgt - 3);
2027 #else
2028                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2029                                x * Infofnt->wid + Infowin->ox,
2030                                y * Infofnt->hgt + Infowin->oy,
2031                                Infofnt->twid - 1, Infofnt->hgt - 1);
2032                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2033                                x * Infofnt->wid + Infowin->ox + 1,
2034                                y * Infofnt->hgt + Infowin->oy + 1,
2035                                Infofnt->twid - 3, Infofnt->hgt - 3);
2036 #endif
2037         }
2038         else
2039         {
2040                 Infoclr_set(xor);
2041                 Infofnt_text_non(x, y, "  ", 2);
2042         }
2043
2044         return (0);
2045 }
2046
2047 /*
2048  * Erase some characters.
2049  */
2050 static errr Term_wipe_x11(int x, int y, int n)
2051 {
2052         Infoclr_set(clr[TERM_DARK]);
2053         Infofnt_text_non(x, y, "", n);
2054         s_ptr->drawn = FALSE;
2055         return (0);
2056 }
2057
2058 /*
2059  * Draw some textual characters.
2060  */
2061 static errr Term_text_x11(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
2062 {
2063         Infoclr_set(clr[a]);
2064         Infofnt_text_std(x, y, s, n);
2065         s_ptr->drawn = FALSE;
2066         return (0);
2067 }
2068
2069 #ifndef USE_XFT
2070 /*
2071  * Draw some graphical characters.
2072  */
2073 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)
2074 {
2075         int i, x1, y1;
2076
2077         TERM_COLOR a;
2078         char c;
2079
2080         TERM_COLOR ta;
2081         char tc;
2082
2083         int x2, y2;
2084         int k,l;
2085
2086         unsigned long pixel, blank;
2087
2088         term_data *td = (term_data*)(Term->data);
2089
2090         y *= Infofnt->hgt;
2091         x *= Infofnt->wid;
2092
2093         y += Infowin->oy;
2094         x += Infowin->ox;
2095         for (i = 0; i < n; ++i, x += td->fnt->wid)
2096         {
2097                 a = *ap++;
2098                 c = *cp++;
2099                 x1 = (c&0x7F) * td->fnt->twid;
2100                 y1 = (a&0x7F) * td->fnt->hgt;
2101                 if (td->tiles->width < x1 + td->fnt->wid ||
2102                     td->tiles->height < y1 + td->fnt->hgt)
2103                 {
2104                         XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc, x, y,  td->fnt->twid, td->fnt->hgt);
2105                         continue;
2106                 }
2107
2108                 ta = *tap++;
2109                 tc = *tcp++;
2110
2111                 x2 = (tc&0x7F) * td->fnt->twid;
2112                 y2 = (ta&0x7F) * td->fnt->hgt;
2113                 
2114                 if (((x1 == x2) && (y1 == y2)) ||
2115                     !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
2116                     td->tiles->width < x2 + td->fnt->wid ||
2117                     td->tiles->height < y2 + td->fnt->hgt)
2118                 {
2119                         XPutImage(Metadpy->dpy, td->win->win,
2120                                 clr[0]->gc,
2121                                 td->tiles,
2122                                 x1, y1,
2123                                 x, y,
2124                                 td->fnt->twid, td->fnt->hgt);   
2125                 }
2126                 else
2127                 {
2128                         blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
2129                         for (k = 0; k < td->fnt->twid; k++)
2130                         {
2131                                 for (l = 0; l < td->fnt->hgt; l++)
2132                                 {
2133                                         if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
2134                                         {
2135                                                 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
2136                                         }
2137                                         
2138                                         XPutPixel(td->TmpImage, k, l, pixel);
2139                                 }
2140                         }
2141
2142                         XPutImage(Metadpy->dpy, td->win->win,
2143                               clr[0]->gc,
2144                              td->TmpImage,
2145                              0, 0, x, y,
2146                              td->fnt->twid, td->fnt->hgt);
2147                 }
2148         }
2149
2150         s_ptr->drawn = FALSE;
2151         return (0);
2152 }
2153 #endif
2154
2155 #ifdef USE_XIM
2156 static void IMDestroyCallback(XIM, XPointer, XPointer);
2157
2158 static void
2159 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
2160 {
2161         XIM xim;
2162         XIMCallback ximcallback;
2163         XIMStyles *xim_styles = NULL;
2164         int i;
2165
2166         (void)unused1;
2167         (void)unused2;
2168
2169         xim = XOpenIM(display, NULL, NULL, NULL);
2170         if(!xim){
2171                 printf("can't open IM\n");
2172                 return;
2173         }
2174
2175         ximcallback.callback = IMDestroyCallback;
2176         ximcallback.client_data = NULL;
2177         XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
2178         XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
2179         for (i = 0; i < xim_styles->count_styles; i++){
2180                 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
2181         }
2182         if(i >= xim_styles->count_styles){
2183                 printf("Sorry, your IM does not support 'Root' preedit style...\n");
2184                 XCloseIM(xim);
2185                 return;
2186         }
2187         XFree(xim_styles);
2188
2189         Metadpy->xim = xim;
2190
2191         for (i = 0; i < MAX_TERM_DATA; i++)
2192         {
2193                 infowin *iwin = data[i].win;
2194                 if (!iwin) continue;
2195                 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
2196                 if(!iwin->xic)
2197                 {
2198                         printf("Can't create input context for Term%d\n", i);
2199                         continue;
2200                 }
2201
2202                 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL)
2203                 {
2204                         iwin->xic_mask = 0L;
2205                 }
2206
2207                 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
2208         }
2209
2210         return;
2211 }
2212
2213 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
2214 {
2215         int i;
2216         (void)xim;
2217         (void)client_data;
2218
2219         if (call_data == NULL){
2220                 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
2221         }
2222
2223         for(i = 0; i < MAX_TERM_DATA; i++)
2224         {
2225                 infowin *iwin = data[i].win;
2226                 if(!iwin) continue;
2227                 if(iwin->xic_mask){
2228                         XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
2229                         iwin->xic_mask = 0L;
2230                 }
2231                 iwin->xic = NULL;
2232         }
2233
2234         Metadpy->xim = NULL;
2235 }
2236 #endif
2237
2238 static char force_lower(char a)
2239 {
2240         return ((isupper((a))) ? tolower((a)) : (a));
2241 }
2242
2243 /*
2244  * Initialize a term_data
2245  */
2246 static errr term_data_init(term_data *td, int i)
2247 {
2248         term_type *t = &td->t;
2249
2250         concptr name = angband_term_name[i];
2251
2252         concptr font;
2253         int x = 0;
2254         int y = 0;
2255
2256         int cols = 80;
2257         int rows = 24;
2258
2259         int ox = 1;
2260         int oy = 1;
2261
2262         int wid, hgt, num;
2263
2264         char buf[80];
2265
2266         concptr str;
2267
2268         int val;
2269
2270         XClassHint *ch;
2271
2272         char res_name[20];
2273         char res_class[20];
2274
2275         XSizeHints *sh;
2276 #ifdef USE_XIM
2277         XWMHints *wh;
2278 #endif
2279
2280         sprintf(buf, "ANGBAND_X11_FONT_%d", i);
2281         font = getenv(buf);
2282         if (!font) font = getenv("ANGBAND_X11_FONT");
2283
2284         if (!font)
2285         {
2286                 switch (i)
2287                 {
2288                         case 0:
2289                         {
2290                                 font = DEFAULT_X11_FONT_0;
2291                         }
2292                         break;
2293                         case 1:
2294                         {
2295                                 font = DEFAULT_X11_FONT_1;
2296                         }
2297                         break;
2298                         case 2:
2299                         {
2300                                 font = DEFAULT_X11_FONT_2;
2301                         }
2302                         break;
2303                         case 3:
2304                         {
2305                                 font = DEFAULT_X11_FONT_3;
2306                         }
2307                         break;
2308                         case 4:
2309                         {
2310                                 font = DEFAULT_X11_FONT_4;
2311                         }
2312                         break;
2313                         case 5:
2314                         {
2315                                 font = DEFAULT_X11_FONT_5;
2316                         }
2317                         break;
2318                         case 6:
2319                         {
2320                                 font = DEFAULT_X11_FONT_6;
2321                         }
2322                         break;
2323                         case 7:
2324                         {
2325                                 font = DEFAULT_X11_FONT_7;
2326                         }
2327                         break;
2328                         default:
2329                         {
2330                                 font = DEFAULT_X11_FONT;
2331                         }
2332                 }
2333         }
2334
2335         sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
2336         str = getenv(buf);
2337         x = (str != NULL) ? atoi(str) : -1;
2338
2339         sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
2340         str = getenv(buf);
2341         y = (str != NULL) ? atoi(str) : -1;
2342
2343         sprintf(buf, "ANGBAND_X11_COLS_%d", i);
2344         str = getenv(buf);
2345         val = (str != NULL) ? atoi(str) : -1;
2346         if (val > 0) cols = val;
2347
2348         sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
2349         str = getenv(buf);
2350         val = (str != NULL) ? atoi(str) : -1;
2351         if (val > 0) rows = val;
2352
2353         if (!i)
2354         {
2355                 if (cols < 80) cols = 80;
2356                 if (rows < 24) rows = 24;
2357         }
2358
2359         sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
2360         str = getenv(buf);
2361         val = (str != NULL) ? atoi(str) : -1;
2362         if (val > 0) ox = val;
2363
2364         sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
2365         str = getenv(buf);
2366         val = (str != NULL) ? atoi(str) : -1;
2367         if (val > 0) oy = val;
2368
2369         MAKE(td->fnt, infofnt);
2370         Infofnt_set(td->fnt);
2371         Infofnt_init_data(font);
2372
2373         num = ((i == 0) ? 1024 : 16);
2374         wid = cols * td->fnt->wid + (ox + ox);
2375         hgt = rows * td->fnt->hgt + (oy + oy);
2376         MAKE(td->win, infowin);
2377         Infowin_set(td->win);
2378         Infowin_init_top(x, y, wid, hgt, 0,
2379                          Metadpy->fg, Metadpy->bg);
2380
2381 #if defined(USE_XIM)
2382         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
2383 #else
2384         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
2385 #endif
2386
2387         Infowin_set_name(name);
2388         Infowin->ox = ox;
2389         Infowin->oy = oy;
2390         ch = XAllocClassHint();
2391
2392         if (ch == NULL) quit("XAllocClassHint failed");
2393
2394         strcpy(res_name, name);
2395         res_name[0] = force_lower(res_name[0]);
2396         ch->res_name = res_name;
2397
2398         strcpy(res_class, "Angband");
2399         ch->res_class = res_class;
2400
2401         XSetClassHint(Metadpy->dpy, Infowin->win, ch);
2402         sh = XAllocSizeHints();
2403         if (sh == NULL) quit("XAllocSizeHints failed");
2404
2405         if (i == 0)
2406         {
2407                 sh->flags = PMinSize | PMaxSize;
2408                 sh->min_width = 80 * td->fnt->wid + (ox + ox);
2409                 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
2410                 sh->max_width = 255 * td->fnt->wid + (ox + ox);
2411                 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
2412         }
2413         else
2414         {
2415                 sh->flags = PMinSize | PMaxSize;
2416                 sh->min_width = td->fnt->wid + (ox + ox);
2417                 sh->min_height = td->fnt->hgt + (oy + oy);
2418                 sh->max_width = 256 * td->fnt->wid + (ox + ox);
2419                 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
2420         }
2421
2422         sh->flags |= PResizeInc;
2423         sh->width_inc = td->fnt->wid;
2424         sh->height_inc = td->fnt->hgt;
2425         sh->flags |= PBaseSize;
2426         sh->base_width = (ox + ox);
2427         sh->base_height = (oy + oy);
2428         XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
2429         Infowin_map();
2430
2431 #ifdef USE_XIM
2432         wh = XAllocWMHints();
2433         if(wh == NULL) quit("XAllocWMHints failed");
2434         wh->flags = InputHint;
2435         wh->input = True;
2436         XSetWMHints(Metadpy->dpy, Infowin->win, wh);
2437 #endif
2438
2439         if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
2440
2441         term_init(t, cols, rows, num);
2442         t->soft_cursor = TRUE;
2443         t->attr_blank = TERM_WHITE;
2444         t->char_blank = ' ';
2445         t->xtra_hook = Term_xtra_x11;
2446         t->curs_hook = Term_curs_x11;
2447         t->bigcurs_hook = Term_bigcurs_x11;
2448         t->wipe_hook = Term_wipe_x11;
2449         t->text_hook = Term_text_x11;
2450         t->data = td;
2451         term_activate(t);
2452         return (0);
2453 }
2454
2455 /*
2456  * Initialization function for an "X11" module to Angband
2457  */
2458 errr init_x11(int argc, char *argv[])
2459 {
2460         int i;
2461         concptr dpy_name = "";
2462         int num_term = 3;
2463
2464 #ifndef USE_XFT
2465         char filename[1024];
2466
2467         int pict_wid = 0;
2468         int pict_hgt = 0;
2469
2470         char *TmpData;
2471 #endif
2472
2473         for (i = 1; i < argc; i++)
2474         {
2475                 if (prefix(argv[i], "-d"))
2476                 {
2477                         dpy_name = &argv[i][2];
2478                         continue;
2479                 }
2480                 
2481 #ifndef USE_XFT
2482                 if (prefix(argv[i], "-s"))
2483                 {
2484                         smoothRescaling = FALSE;
2485                         continue;
2486                 }
2487
2488                 if (prefix(argv[i], "-a"))
2489                 {
2490                         arg_graphics = GRAPHICS_ADAM_BOLT;
2491                         continue;
2492                 }
2493
2494                 if (prefix(argv[i], "-o"))
2495                 {
2496                         arg_graphics = GRAPHICS_ORIGINAL;
2497                         continue;
2498                 }
2499 #endif
2500
2501                 if (prefix(argv[i], "-b"))
2502                 {
2503                         arg_bigtile = use_bigtile = TRUE;
2504                         continue;
2505                 }
2506
2507                 if (prefix(argv[i], "-n"))
2508                 {
2509                         num_term = atoi(&argv[i][2]);
2510                         if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
2511                         else if (num_term < 1) num_term = 1;
2512                         continue;
2513                 }
2514
2515                 if (prefix(argv[i], "--"))
2516                 {
2517                         continue;
2518                 }
2519
2520                 plog_fmt("Ignoring option: %s", argv[i]);
2521         }
2522
2523 #ifdef USE_LOCALE
2524
2525 #ifdef JP
2526         setlocale(LC_ALL, "");
2527
2528 #ifdef DEFAULT_LOCALE
2529         if(!strcmp(setlocale(LC_ALL, NULL), "C")){
2530                 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
2531                 setlocale(LC_ALL, DEFAULT_LOCALE);
2532         }
2533 #endif
2534
2535         if(!strcmp(setlocale(LC_ALL, NULL), "C"))
2536         {
2537                 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
2538         }
2539
2540         if(!XSupportsLocale()){
2541                 printf("can't support locale in X\n");
2542                 setlocale(LC_ALL, "C");
2543         }
2544 #else
2545         setlocale(LC_ALL, "C");
2546 #endif /* JP */
2547
2548 #endif /* USE_LOCALE */
2549
2550         if (Metadpy_init_name(dpy_name)) return (-1);
2551
2552         MAKE(xor, infoclr);
2553         Infoclr_set(xor);
2554         Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
2555         for (i = 0; i < 256; ++i)
2556         {
2557                 Pixell pixel;
2558                 MAKE(clr[i], infoclr);
2559                 Infoclr_set(clr[i]);
2560                 color_table[i][0] = angband_color_table[i][0];
2561                 color_table[i][1] = angband_color_table[i][1];
2562                 color_table[i][2] = angband_color_table[i][2];
2563                 color_table[i][3] = angband_color_table[i][3];
2564                 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
2565                 if (Metadpy->color)
2566                 {
2567                         pixel = create_pixel(Metadpy->dpy,
2568                                              color_table[i][1],
2569                                              color_table[i][2],
2570                                              color_table[i][3]);
2571                 }
2572
2573                 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
2574         }
2575
2576         set_atoms();
2577         for (i = 0; i < num_term; i++)
2578         {
2579                 term_data *td = &data[i];
2580                 term_data_init(td, i);
2581                 angband_term[i] = Term;
2582         }
2583
2584         Infowin_set(data[0].win);
2585         Infowin_raise();
2586         term_activate(&data[0].t);
2587
2588 #ifdef USE_XIM
2589         {
2590                 char *p;
2591                 p = XSetLocaleModifiers("");
2592                 if(!p || !*p){
2593                         p = XSetLocaleModifiers("@im=");
2594                 }
2595         }
2596         XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
2597 #endif
2598
2599         if (arg_sound) init_sound();
2600
2601 #ifndef USE_XFT
2602         switch (arg_graphics)
2603         {
2604         case GRAPHICS_ORIGINAL:
2605                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
2606                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
2607                 {
2608                         use_graphics = TRUE;
2609                         pict_wid = pict_hgt = 8;
2610                         ANGBAND_GRAF = "old";
2611                 }
2612                 break;
2613         case GRAPHICS_ADAM_BOLT:
2614                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
2615                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
2616                 {
2617                         use_graphics = TRUE;
2618                         pict_wid = pict_hgt = 16;
2619                         ANGBAND_GRAF = "new";
2620                 }
2621                 break;
2622         }
2623
2624         if (use_graphics)
2625         {
2626                 Display *dpy = Metadpy->dpy;
2627                 XImage *tiles_raw;
2628                 tiles_raw = ReadBMP(dpy, filename);
2629                 for (i = 0; i < num_term; i++)
2630                 {
2631                         term_data *td = &data[i];
2632                         term_type *t = &td->t;
2633                         t->pict_hook = Term_pict_x11;
2634                         t->higher_pict = TRUE;
2635                         td->tiles =
2636                         ResizeImage(dpy, tiles_raw,
2637                                     pict_wid, pict_hgt,
2638                                     td->fnt->twid, td->fnt->hgt);
2639                 }
2640
2641                 for (i = 0; i < num_term; i++)
2642                 {
2643                         term_data *td = &data[i];
2644                         int ii, jj;
2645                         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
2646                         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
2647                         int total;
2648                         ii = 1;
2649                         jj = (depth - 1) >> 2;
2650                         while (jj >>= 1) ii <<= 1;
2651                         total = td->fnt->twid * td->fnt->hgt * ii;
2652                         TmpData = (char *)malloc(total);
2653                         td->TmpImage = XCreateImage(dpy,visual,depth,
2654                                 ZPixmap, 0, TmpData,
2655                                 td->fnt->twid, td->fnt->hgt, 8, 0);
2656                 }
2657         }
2658 #endif /* ! USE_XFT */
2659         return (0);
2660 }
2661
2662 #endif /* USE_X11 */