OSDN Git Service

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