OSDN Git Service

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