OSDN Git Service

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