OSDN Git Service

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