OSDN Git Service

[Refactor] #37353 使われていないプリプロDEBUG_EVENT を削除 / Removed unused preprocessor DEBUG_EVENT
[hengband/hengband.git] / src / main-x11.c
1 /* File: main-x11.c */
2
3 /*
4  * Copyright (c) 1997 Ben Harrison, and others
5  *
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.
9  */
10
11
12 /*
13  * This file helps Angband work with UNIX/X11 computers.
14  *
15  * To use this file, compile with "USE_X11" defined, and link against all
16  * the various "X11" libraries which may be needed.
17  *
18  * See also "main-xaw.c".
19  *
20  * Part of this file provides a user interface package composed of several
21  * pseudo-objects, including "metadpy" (a display), "infowin" (a window),
22  * "infoclr" (a color), and "infofnt" (a font).  Actually, the package was
23  * originally much more interesting, but it was bastardized to keep this
24  * file simple.
25  *
26  * The rest of this file is an implementation of "main-xxx.c" for X11.
27  *
28  * Most of this file is by Ben Harrison (benh@phial.com).
29  */
30
31 /*
32  * The following shell script can be used to launch Angband, assuming that
33  * it was extracted into "~/Angband", and compiled using "USE_X11", on a
34  * Linux machine, with a 1280x1024 screen, using 6 windows (with the given
35  * characteristics), with gamma correction of 1.8 -> (1 / 1.8) * 256 = 142,
36  * and without graphics (add "-g" for graphics).  Just copy this comment
37  * into a file, remove the leading " * " characters (and the head/tail of
38  * this comment), and make the file executable.
39  * 
40  *
41  * #!/bin/csh
42  * 
43  * # Describe attempt
44  * echo "Launching angband..."
45  * sleep 2
46  * 
47  * # Main window
48  * setenv ANGBAND_X11_FONT_0 10x20
49  * setenv ANGBAND_X11_AT_X_0 5
50  * setenv ANGBAND_X11_AT_Y_0 510
51  * 
52  * # Message window
53  * setenv ANGBAND_X11_FONT_1 8x13
54  * setenv ANGBAND_X11_AT_X_1 5
55  * setenv ANGBAND_X11_AT_Y_1 22
56  * setenv ANGBAND_X11_ROWS_1 35
57  * 
58  * # Inventory window
59  * setenv ANGBAND_X11_FONT_2 8x13
60  * setenv ANGBAND_X11_AT_X_2 635
61  * setenv ANGBAND_X11_AT_Y_2 182
62  * setenv ANGBAND_X11_ROWS_3 23
63  * 
64  * # Equipment window
65  * setenv ANGBAND_X11_FONT_3 8x13
66  * setenv ANGBAND_X11_AT_X_3 635
67  * setenv ANGBAND_X11_AT_Y_3 22
68  * setenv ANGBAND_X11_ROWS_3 12
69  * 
70  * # Monster recall window
71  * setenv ANGBAND_X11_FONT_4 6x13
72  * setenv ANGBAND_X11_AT_X_4 817
73  * setenv ANGBAND_X11_AT_Y_4 847
74  * setenv ANGBAND_X11_COLS_4 76
75  * setenv ANGBAND_X11_ROWS_4 11
76  * 
77  * # Object recall window
78  * setenv ANGBAND_X11_FONT_5 6x13
79  * setenv ANGBAND_X11_AT_X_5 817
80  * setenv ANGBAND_X11_AT_Y_5 520
81  * setenv ANGBAND_X11_COLS_5 76
82  * setenv ANGBAND_X11_ROWS_5 24
83  * 
84  * # The build directory
85  * cd ~/Angband
86  *
87  * # Gamma correction
88  * setenv ANGBAND_X11_GAMMA 142
89  * 
90  * # Launch Angband
91  * ./src/angband -mx11 -- -n6 &
92  *
93  */
94
95
96 #include "angband.h"
97 #include "core.h"
98 #include "files.h"
99 #include "term.h"
100
101
102 /*
103  * Available graphic modes
104  */
105 #define GRAPHICS_NONE       0
106 #define GRAPHICS_ORIGINAL   1
107 #define GRAPHICS_ADAM_BOLT  2
108 #define GRAPHICS_HENGBAND   3
109 #ifdef USE_X11
110
111
112 #ifndef __MAKEDEPEND__
113 #include <X11/Xlib.h>
114 #include <X11/Xutil.h>
115 #include <X11/keysym.h>
116 #include <X11/keysymdef.h>
117 #ifdef USE_LOCALE
118 #include <X11/Xlocale.h>
119 #endif
120 #include <X11/Xatom.h>
121 #endif /* __MAKEDEPEND__ */
122
123 #include <iconv.h>
124 /*
125  * Include some helpful X11 code.
126  */
127 #include "maid-x11.c"
128
129
130 /*
131  * Notes on Colors:
132  *
133  *   1) On a monochrome (or "fake-monochrome") display, all colors
134  *   will be "cast" to "fg," except for the bg color, which is,
135  *   obviously, cast to "bg".  Thus, one can ignore this setting.
136  *
137  *   2) Because of the inner functioning of the color allocation
138  *   routines, colors may be specified as (a) a typical color name,
139  *   (b) a hexidecimal color specification (preceded by a pound sign),
140  *   or (c) by strings such as "fg", "bg", "zg".
141  *
142  *   3) Due to the workings of the init routines, many colors
143  *   may also be dealt with by their actual pixel values.  Note that
144  *   the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
145  *   is not necessarily either black or white.
146  */
147
148 /**** Generic Types ****/
149
150 /*
151  * An X11 pixell specifier
152  */
153 typedef unsigned long Pixell;
154
155 /*
156  * The structures defined below
157  */
158 typedef struct metadpy metadpy;
159 typedef struct infowin infowin;
160 typedef struct infoclr infoclr;
161 typedef struct infofnt infofnt;
162
163
164 /*
165  * A structure summarizing a given Display.
166  *
167  *      - The Display itself
168  *      - The default Screen for the display
169  *      - The virtual root (usually just the root)
170  *      - The default colormap (from a macro)
171  *
172  *      - The "name" of the display
173  *
174  *      - The socket to listen to for events
175  *
176  *      - The width of the display screen (from a macro)
177  *      - The height of the display screen (from a macro)
178  *      - The bit depth of the display screen (from a macro)
179  *
180  *      - The black Pixell (from a macro)
181  *      - The white Pixell (from a macro)
182  *
183  *      - The background Pixell (default: black)
184  *      - The foreground Pixell (default: white)
185  *      - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
186  *
187  *      - Bit Flag: Force all colors to black and white (default: !color)
188  *      - Bit Flag: Allow the use of color (default: depth > 1)
189  *      - Bit Flag: We created 'dpy', and so should nuke it when done.
190  */
191 struct metadpy
192 {
193         Display *dpy;
194         Screen *screen;
195         Window root;
196         Colormap cmap;
197 #ifdef USE_XIM
198         XIM xim;
199 #endif
200
201         char *name;
202
203         int fd;
204
205         uint width;
206         uint height;
207         uint depth;
208
209         Pixell black;
210         Pixell white;
211
212         Pixell bg;
213         Pixell fg;
214         Pixell zg;
215
216         uint mono:1;
217         uint color:1;
218         uint nuke:1;
219 };
220
221
222
223 /*
224  * A Structure summarizing Window Information.
225  *
226  * I assume that a window is at most 30000 pixels on a side.
227  * I assume that the root windw is also at most 30000 square.
228  *
229  *      - The Window
230  *      - The current Input Event Mask
231  *
232  *      - The location of the window
233  *      - The width, height of the window
234  *      - The border width of this window
235  *
236  *      - Byte: 1st Extra byte
237  *
238  *      - Bit Flag: This window is currently Mapped
239  *      - Bit Flag: This window needs to be redrawn
240  *      - Bit Flag: This window has been resized
241  *
242  *      - Bit Flag: We should nuke 'win' when done with it
243  *
244  *      - Bit Flag: 1st extra flag
245  *      - Bit Flag: 2nd extra flag
246  *      - Bit Flag: 3rd extra flag
247  *      - Bit Flag: 4th extra flag
248  */
249 struct infowin
250 {
251         Window win;
252 #ifdef USE_XIM
253         XIC xic;
254         long xic_mask;
255 #endif
256
257         long mask;
258
259         s16b ox, oy;
260
261         s16b x, y;
262         s16b w, h;
263         u16b b;
264
265         byte byte1;
266
267         uint mapped:1;
268         uint redraw:1;
269         uint resize:1;
270
271         uint nuke:1;
272
273         uint flag1:1;
274         uint flag2:1;
275         uint flag3:1;
276         uint flag4:1;
277 };
278
279
280
281
282
283
284 /*
285  * A Structure summarizing Operation+Color Information
286  *
287  *      - The actual GC corresponding to this info
288  *
289  *      - The Foreground Pixell Value
290  *      - The Background Pixell Value
291  *
292  *      - Num (0-15): The operation code (As in Clear, Xor, etc)
293  *      - Bit Flag: The GC is in stipple mode
294  *      - Bit Flag: Destroy 'gc' at Nuke time.
295  */
296 struct infoclr
297 {
298         GC gc;
299
300         Pixell fg;
301         Pixell bg;
302
303         uint code:4;
304         uint stip:1;
305         uint nuke:1;
306 };
307
308
309
310 /*
311  * A Structure to Hold Font Information
312  *
313  *      - The 'XFontStruct*' (yields the 'Font')
314  *
315  *      - The font name
316  *
317  *      - The default character width
318  *      - The default character height
319  *      - The default character ascent
320  *
321  *      - Byte: Pixel offset used during fake mono
322  *
323  *      - Flag: Force monospacing via 'wid'
324  *      - Flag: Nuke info when done
325  */
326 struct infofnt
327 {
328         XFontSet info;
329         concptr name;
330
331         s16b wid;
332         s16b twid;
333         s16b hgt;
334         s16b asc;
335
336         byte off;
337
338         uint mono:1;
339         uint nuke:1;
340 };
341
342
343
344
345 /**** Generic Macros ****/
346
347
348
349 /* Set current metadpy (Metadpy) to 'M' */
350 #define Metadpy_set(M) \
351         Metadpy = M
352
353
354 /* Initialize 'M' using Display 'D' */
355 #define Metadpy_init_dpy(D) \
356         Metadpy_init_2(D,cNULL)
357
358 /* Initialize 'M' using a Display named 'N' */
359 #define Metadpy_init_name(N) \
360         Metadpy_init_2((Display*)(NULL),N)
361
362 /* Initialize 'M' using the standard Display */
363 #define Metadpy_init() \
364         Metadpy_init_name("")
365
366
367 /* Init an infowin by giving father as an (info_win*) (or NULL), and data */
368 #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
369         Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
370                           X,Y,W,H,B,FG,BG)
371
372
373 /* Init a top level infowin by pos,size,bord,Colors */
374 #define Infowin_init_top(X,Y,W,H,B,FG,BG) \
375         Infowin_init_data(None,X,Y,W,H,B,FG,BG)
376
377
378 /* Request a new standard window by giving Dad infowin and X,Y,W,H */
379 #define Infowin_init_std(D,X,Y,W,H,B) \
380         Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
381
382
383 /* Set the current Infowin */
384 #define Infowin_set(I) \
385         (Infowin = (I))
386
387
388 /* Set the current Infoclr */
389 #define Infoclr_set(C) \
390         (Infoclr = (C))
391
392
393 #define Infoclr_init_ppo(F,B,O,M) \
394         Infoclr_init_data(F,B,O,M)
395
396 #define Infoclr_init_cco(F,B,O,M) \
397         Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
398
399 #define Infoclr_init_ppn(F,B,O,M) \
400         Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
401
402 #define Infoclr_init_ccn(F,B,O,M) \
403         Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
404
405
406 /* Set the current infofnt */
407 #define Infofnt_set(I) \
408         (Infofnt = (I))
409
410
411 /* Errr: Expose Infowin */
412 #define Infowin_expose() \
413         (!(Infowin->redraw = 1))
414
415 /* Errr: Unxpose Infowin */
416 #define Infowin_unexpose() \
417         (Infowin->redraw = 0)
418
419
420
421 /**** Generic Globals ****/
422
423
424 /*
425  * The "default" values
426  */
427 static metadpy metadpy_default;
428
429
430 /*
431  * The "current" variables
432  */
433 static metadpy *Metadpy = &metadpy_default;
434 static infowin *Infowin = (infowin*)(NULL);
435 #ifdef USE_XIM
436 static infowin *Focuswin = (infowin*)(NULL);
437 #endif
438 static infoclr *Infoclr = (infoclr*)(NULL);
439 static infofnt *Infofnt = (infofnt*)(NULL);
440
441 /**** Generic code ****/
442
443 /*
444  * Init the current metadpy, with various initialization stuff.
445  *
446  * Inputs:
447  *      dpy:  The Display* to use (if NULL, create it)
448  *      name: The name of the Display (if NULL, the current)
449  *
450  * Notes:
451  *      If 'name' is NULL, but 'dpy' is set, extract name from dpy
452  *      If 'dpy' is NULL, then Create the named Display
453  *      If 'name' is NULL, and so is 'dpy', use current Display
454  *
455  * Return -1 if no Display given, and none can be opened.
456  */
457 static errr Metadpy_init_2(Display *dpy, concptr name)
458 {
459         metadpy *m = Metadpy;
460
461         /*** Open the display if needed ***/
462
463         /* If no Display given, attempt to Create one */
464         if (!dpy)
465         {
466                 /* Attempt to open the display */
467                 dpy = XOpenDisplay(name);
468
469                 /* Failure */
470                 if (!dpy) return (-1);
471
472                 /* We will have to nuke it when done */
473                 m->nuke = 1;
474         }
475
476         /* Since the Display was given, use it */
477         else
478         {
479                 /* We will not have to nuke it when done */
480                 m->nuke = 0;
481         }
482
483
484         /*** Save some information ***/
485
486         /* Save the Display itself */
487         m->dpy = dpy;
488
489         /* Get the Screen and Virtual Root Window */
490         m->screen = DefaultScreenOfDisplay(dpy);
491         m->root = RootWindowOfScreen(m->screen);
492
493         /* Get the default colormap */
494         m->cmap = DefaultColormapOfScreen(m->screen);
495
496         /* Extract the true name of the display */
497         m->name = DisplayString(dpy);
498
499         /* Extract the fd */
500         m->fd = ConnectionNumber(Metadpy->dpy);
501
502         /* Save the Size and Depth of the screen */
503         m->width = WidthOfScreen(m->screen);
504         m->height = HeightOfScreen(m->screen);
505         m->depth = DefaultDepthOfScreen(m->screen);
506
507         /* Save the Standard Colors */
508         m->black = BlackPixelOfScreen(m->screen);
509         m->white = WhitePixelOfScreen(m->screen);
510
511         /*** Make some clever Guesses ***/
512
513         /* Guess at the desired 'fg' and 'bg' Pixell's */
514         m->bg = m->black;
515         m->fg = m->white;
516
517         /* Calculate the Maximum allowed Pixel value.  */
518         m->zg = (1 << m->depth) - 1;
519
520         /* Save various default Flag Settings */
521         m->color = ((m->depth > 1) ? 1 : 0);
522         m->mono = ((m->color) ? 0 : 1);
523
524         /* Return "success" */
525         return (0);
526 }
527
528
529 /*
530  * General Flush/ Sync/ Discard routine
531  */
532 static errr Metadpy_update(int flush, int sync, int discard)
533 {
534         /* Flush if desired */
535         if (flush) XFlush(Metadpy->dpy);
536
537         /* Sync if desired, using 'discard' */
538         if (sync) XSync(Metadpy->dpy, discard);
539
540         /* Success */
541         return (0);
542 }
543
544
545 /*
546  * Make a simple beep
547  */
548 static errr Metadpy_do_beep(void)
549 {
550         /* Make a simple beep */
551         XBell(Metadpy->dpy, 100);
552
553         return (0);
554 }
555
556
557
558 /*
559  * Set the name (in the title bar) of Infowin
560  */
561 static errr Infowin_set_name(concptr name)
562 {
563         Status st;
564         XTextProperty tp;
565         char buf[128];
566         char *bp = buf;
567         strcpy(buf, name);
568         st = XStringListToTextProperty(&bp, 1, &tp);
569         if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
570         return (0);
571 }
572
573
574 /*
575  * Prepare a new 'infowin'.
576  */
577 static errr Infowin_prepare(Window xid)
578 {
579         infowin *iwin = Infowin;
580
581         Window tmp_win;
582         XWindowAttributes xwa;
583         int x, y;
584         unsigned int w, h, b, d;
585
586         /* Assign stuff */
587         iwin->win = xid;
588
589         /* Check For Error XXX Extract some ACTUAL data from 'xid' */
590         XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
591
592         /* Apply the above info */
593         iwin->x = x;
594         iwin->y = y;
595         iwin->w = w;
596         iwin->h = h;
597         iwin->b = b;
598
599         /* Check Error XXX Extract some more ACTUAL data */
600         XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
601
602         /* Apply the above info */
603         iwin->mask = xwa.your_event_mask;
604         iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
605
606         /* And assume that we are exposed */
607         iwin->redraw = 1;
608
609         /* Success */
610         return (0);
611 }
612
613
614 /*
615  * Init an infowin by giving some data.
616  *
617  * Inputs:
618  *      dad: The Window that should own this Window (if any)
619  *      x,y: The position of this Window
620  *      w,h: The size of this Window
621  *      b,d: The border width and pixel depth
622  *
623  * Notes:
624  *      If 'dad == None' assume 'dad == root'
625  */
626 static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
627                               int b, Pixell fg, Pixell bg)
628 {
629         Window xid;
630
631         /* Wipe it clean */
632         (void)WIPE(Infowin, infowin);
633
634
635         /*** Error Check XXX ***/
636
637
638         /*** Create the Window 'xid' from data ***/
639
640         /* What happened here?  XXX XXX XXX */
641
642         /* If no parent given, depend on root */
643         if (dad == None)
644
645         /* Create the Window XXX Error Check */
646         xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
647
648         /* Start out selecting No events */
649         XSelectInput(Metadpy->dpy, xid, 0L);
650
651
652         /*** Prepare the new infowin ***/
653
654         /* Mark it as nukable */
655         Infowin->nuke = 1;
656
657         /* Attempt to Initialize the infowin */
658         return (Infowin_prepare(xid));
659 }
660
661
662
663 /*
664  * Modify the event mask of an Infowin
665  */
666 static errr Infowin_set_mask(long mask)
667 {
668         /* Save the new setting */
669         Infowin->mask = mask;
670
671         /* Execute the Mapping */
672         XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
673
674         /* Success */
675         return (0);
676 }
677
678
679 /*
680  * Request that Infowin be mapped
681  */
682 static errr Infowin_map(void)
683 {
684         /* Execute the Mapping */
685         XMapWindow(Metadpy->dpy, Infowin->win);
686
687         /* Success */
688         return (0);
689 }
690
691
692 /*
693  * Request that Infowin be raised
694  */
695 static errr Infowin_raise(void)
696 {
697         /* Raise towards visibility */
698         XRaiseWindow(Metadpy->dpy, Infowin->win);
699
700         /* Success */
701         return (0);
702 }
703
704
705 /*
706  * Request that Infowin be moved to a new location
707  */
708 static errr Infowin_impell(int x, int y)
709 {
710         /* Execute the request */
711         XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
712
713         /* Success */
714         return (0);
715 }
716
717
718 /*
719  * Resize an infowin
720  */
721 static errr Infowin_resize(int w, int h)
722 {
723         /* Execute the request */
724         XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
725
726         /* Success */
727         return (0);
728 }
729
730
731 /*
732  * Visually clear Infowin
733  */
734 static errr Infowin_wipe(void)
735 {
736         /* Execute the request */
737         XClearWindow(Metadpy->dpy, Infowin->win);
738
739         /* Success */
740         return (0);
741 }
742
743
744 /*
745  * A NULL terminated pair list of legal "operation names"
746  *
747  * Pairs of values, first is texttual name, second is the string
748  * holding the decimal value that the operation corresponds to.
749  */
750 static concptr opcode_pairs[] =
751 {
752         "cpy", "3",
753         "xor", "6",
754         "and", "1",
755         "ior", "7",
756         "nor", "8",
757         "inv", "10",
758         "clr", "0",
759         "set", "15",
760
761         "src", "3",
762         "dst", "5",
763
764         "+andReverse", "2",
765         "+andInverted", "4",
766         "+noop", "5",
767         "+equiv", "9",
768         "+orReverse", "11",
769         "+copyInverted", "12",
770         "+orInverted", "13",
771         "+nand", "14",
772         NULL
773 };
774
775
776 /*
777  * Parse a word into an operation "code"
778  *
779  * Inputs:
780  *      str: A string, hopefully representing an Operation
781  *
782  * Output:
783  *      0-15: if 'str' is a valid Operation
784  *      -1:   if 'str' could not be parsed
785  */
786 static int Infoclr_Opcode(concptr str)
787 {
788         register int i;
789
790         /* Scan through all legal operation names */
791         for (i = 0; opcode_pairs[i*2]; ++i)
792         {
793                 /* Is this the right oprname? */
794                 if (streq(opcode_pairs[i*2], str))
795                 {
796                         /* Convert the second element in the pair into a Code */
797                         return (atoi(opcode_pairs[i*2+1]));
798                 }
799         }
800
801         /* The code was not found, return -1 */
802         return (-1);
803 }
804
805
806 /*
807  * Initialize an infoclr with some data
808  *
809  * Inputs:
810  *      fg:   The Pixell for the requested Foreground (see above)
811  *      bg:   The Pixell for the requested Background (see above)
812  *      op:   The Opcode for the requested Operation (see above)
813  *      stip: The stipple mode
814  */
815 static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
816 {
817         infoclr *iclr = Infoclr;
818
819         GC gc;
820         XGCValues gcv;
821         unsigned long gc_mask;
822
823
824
825         /*** Simple error checking of opr and clr ***/
826
827         /* Check the 'Pixells' for realism */
828         if (bg > Metadpy->zg) return (-1);
829         if (fg > Metadpy->zg) return (-1);
830
831         /* Check the data for trueness */
832         if ((op < 0) || (op > 15)) return (-1);
833
834
835         /*** Create the requested 'GC' ***/
836
837         /* Assign the proper GC function */
838         gcv.function = op;
839
840         /* Assign the proper GC background */
841         gcv.background = bg;
842
843         /* Assign the proper GC foreground */
844         gcv.foreground = fg;
845
846         /* Hack -- Handle XOR (xor is code 6) by hacking bg and fg */
847         if (op == 6) gcv.background = 0;
848         if (op == 6) gcv.foreground = (bg ^ fg);
849
850         /* Assign the proper GC Fill Style */
851         gcv.fill_style = (stip ? FillStippled : FillSolid);
852
853         /* Turn off 'Give exposure events for pixmap copying' */
854         gcv.graphics_exposures = False;
855
856         /* Set up the GC mask */
857         gc_mask = (GCFunction | GCBackground | GCForeground |
858                    GCFillStyle | GCGraphicsExposures);
859
860         /* Create the GC detailed above */
861         gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
862
863
864         /*** Initialize ***/
865
866         /* Wipe the iclr clean */
867         (void)WIPE(iclr, infoclr);
868
869         /* Assign the GC */
870         iclr->gc = gc;
871
872         /* Nuke it when done */
873         iclr->nuke = 1;
874
875         /* Assign the parms */
876         iclr->fg = fg;
877         iclr->bg = bg;
878         iclr->code = op;
879         iclr->stip = stip ? 1 : 0;
880
881         /* Success */
882         return (0);
883 }
884
885
886
887 /*
888  * Change the 'fg' for an infoclr
889  *
890  * Inputs:
891  *      fg:   The Pixell for the requested Foreground (see above)
892  */
893 static errr Infoclr_change_fg(Pixell fg)
894 {
895         infoclr *iclr = Infoclr;
896
897
898         /*** Simple error checking of opr and clr ***/
899
900         /* Check the 'Pixells' for realism */
901         if (fg > Metadpy->zg) return (-1);
902
903
904         /*** Change ***/
905
906         /* Change */
907         XSetForeground(Metadpy->dpy, iclr->gc, fg);
908
909         /* Success */
910         return (0);
911 }
912
913
914 /*
915  * Prepare a new 'infofnt'
916  */
917 static errr Infofnt_prepare(XFontSet info)
918 {
919         infofnt *ifnt = Infofnt;
920
921         XCharStruct *cs;
922         XFontStruct **fontinfo;
923         char **fontname;
924         int n_fonts;
925         int ascent, descent, width;
926
927         /* Assign the struct */
928         ifnt->info = info;
929
930         n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);
931
932         ascent = descent = width = 0;
933         while(n_fonts-- > 0){
934                 cs = &((*fontinfo)->max_bounds);
935                 if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
936                 if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
937                 if(((*fontinfo)->max_byte1) > 0){
938                         /* 多バイト文字の場合は幅半分(端数切り上げ)で評価する */
939                         if(width < (cs->width+1)/2) width = (cs->width+1)/2;
940                 }else{
941                         if(width < cs->width) width = cs->width;
942                 }
943                 fontinfo++;
944                 fontname++;
945         }
946         ifnt->asc = ascent;
947         ifnt->hgt = ascent + descent;
948         ifnt->wid = width;
949
950         if (use_bigtile)
951                 ifnt->twid = 2 * ifnt->wid;
952         else
953                 ifnt->twid = ifnt->wid;
954
955 #ifndef JP
956 #endif
957
958         /* Success */
959         return (0);
960 }
961
962
963 /*
964  * Init an infofnt by its Name
965  *
966  * Inputs:
967  *      name: The name of the requested Font
968  */
969 static void Infofnt_init_data(concptr name)
970
971 {
972         XFontSet info;
973         char **missing_list;
974         int missing_count;
975         char *default_font;
976
977         /*** Load the info Fresh, using the name ***/
978
979         /* If the name is not given, report an error */
980         if (!name || !*name) quit("Missing font!");
981
982         /* Attempt to load the font */
983         info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
984         if(missing_count > 0){
985                 printf("missing font(s): \n");
986                 while(missing_count-- > 0){
987                         printf("\t%s\n", missing_list[missing_count]);
988                 }
989                 XFreeStringList(missing_list);
990         }
991
992         /* The load failed, try to recover */
993         if (!info) quit_fmt("Failed to find font:\"%s\"", name);
994
995         /*** Init the font ***/
996
997         /* Wipe the thing */
998         (void)WIPE(Infofnt, infofnt);
999
1000         /* Attempt to prepare it */
1001         if (Infofnt_prepare(info))
1002         {
1003                 /* Free the font */
1004                 XFreeFontSet(Metadpy->dpy, info);
1005
1006                 /* Fail */
1007                 quit_fmt("Failed to prepare font:\"%s\"", name);
1008         }
1009
1010         /* Save a copy of the font name */
1011         Infofnt->name = string_make(name);
1012
1013         /* Mark it as nukable */
1014         Infofnt->nuke = 1;
1015 }
1016
1017
1018 /*
1019  * Standard Text
1020  */
1021 static errr Infofnt_text_std(int x, int y, concptr str, int len)
1022 {
1023         int i;
1024
1025
1026         /*** Do a brief info analysis ***/
1027
1028         /* Do nothing if the string is null */
1029         if (!str || !*str) return (-1);
1030
1031         /* Get the length of the string */
1032         if (len < 0) len = strlen(str);
1033
1034         /*** Decide where to place the string, vertically ***/
1035
1036         /* Ignore Vertical Justifications */
1037         y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
1038
1039
1040         /*** Decide where to place the string, horizontally ***/
1041
1042         /* Line up with x at left edge of column 'x' */
1043         x = (x * Infofnt->wid) + Infowin->ox;
1044
1045
1046         /*** Actually draw 'str' onto the infowin ***/
1047
1048         /*** Handle the fake mono we can enforce on fonts ***/
1049
1050         /* Monotize the font */
1051         if (Infofnt->mono)
1052         {
1053                 /* Do each character */
1054                 for (i = 0; i < len; ++i)
1055                 {
1056                         /* Note that the Infoclr is set up to contain the Infofnt */
1057                         XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1058                                          x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
1059                 }
1060         }
1061
1062         /* Assume monoospaced font */
1063         else
1064         {
1065                 /* Note that the Infoclr is set up to contain the Infofnt */
1066                 iconv_t cd = iconv_open("UTF-8", "EUC-JP");
1067                 size_t inlen = len;
1068                 size_t outlen = len * 2;
1069                 char *kanji = malloc(outlen);
1070                 char *sp; char *kp = kanji;
1071                 char sbuf[1024];
1072                 my_strcpy(sbuf, str, sizeof(sbuf));
1073                 sp = sbuf;
1074                 iconv(cd, &sp, &inlen, &kp, &outlen);
1075                 iconv_close(cd);
1076
1077                 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
1078                                 Infoclr->gc, x, y, kanji, kp-kanji);
1079                 free(kanji);
1080         }
1081
1082         /* Success */
1083         return (0);
1084 }
1085
1086
1087 /*
1088  * Painting where text would be
1089  */
1090 static errr Infofnt_text_non(int x, int y, concptr str, int len)
1091 {
1092         int w, h;
1093
1094
1095         /*** Find the width ***/
1096
1097         /* Negative length is a flag to count the characters in str */
1098         if (len < 0) len = strlen(str);
1099
1100         /* The total width will be 'len' chars * standard width */
1101         w = len * Infofnt->wid;
1102
1103
1104         /*** Find the X dimensions ***/
1105
1106         /* Line up with x at left edge of column 'x' */
1107         x = x * Infofnt->wid + Infowin->ox;
1108
1109
1110         /*** Find other dimensions ***/
1111
1112         /* Simply do 'Infofnt->hgt' (a single row) high */
1113         h = Infofnt->hgt;
1114
1115         /* Simply do "at top" in row 'y' */
1116         y = y * h + Infowin->oy;
1117
1118
1119         /*** Actually 'paint' the area ***/
1120
1121         /* Just do a Fill Rectangle */
1122         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
1123
1124         /* Success */
1125         return (0);
1126 }
1127
1128
1129
1130 /*************************************************************************/
1131
1132
1133 /*
1134  * Angband specific code follows... (ANGBAND)
1135  */
1136
1137
1138 /*
1139  * Hack -- cursor color
1140  */
1141 static infoclr *xor;
1142
1143 /*
1144  * Actual color table
1145  */
1146 static infoclr *clr[256];
1147
1148 /*
1149  * Color info (unused, red, green, blue).
1150  */
1151 static byte color_table[256][4];
1152
1153 /*
1154  * Forward declare
1155  */
1156 typedef struct term_data term_data;
1157
1158 /*
1159  * A structure for each "term"
1160  */
1161 struct term_data
1162 {
1163         term t;
1164
1165         infofnt *fnt;
1166         infowin *win;
1167
1168         XImage *tiles;
1169
1170         /* Tempory storage for overlaying tiles. */
1171         XImage *TmpImage;
1172 };
1173
1174
1175 /*
1176  * The number of term data structures
1177  */
1178 #define MAX_TERM_DATA 8
1179
1180 /*
1181  * The array of term data structures
1182  */
1183 static term_data data[MAX_TERM_DATA];
1184
1185
1186 /* Use short names for the most commonly used elements of various structures. */
1187 #define DPY (Metadpy->dpy)
1188 #define WIN (Infowin->win)
1189
1190
1191 /* Describe a set of co-ordinates. */
1192 typedef struct co_ord co_ord;
1193 struct co_ord
1194 {
1195         int x;
1196         int y;
1197 };
1198
1199
1200 /*
1201  * A special structure to store information about the text currently
1202  * selected.
1203  */
1204 typedef struct x11_selection_type x11_selection_type;
1205 struct x11_selection_type
1206 {
1207         bool select; /* The selection is currently in use. */
1208         bool drawn; /* The selection is currently displayed. */
1209         term *t; /* The window where the selection is found. */
1210         co_ord init; /* The starting co-ordinates. */
1211         co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1212         co_ord old; /* The previous end co-ordinates. */
1213         Time time; /* The time at which the selection was finalised. */
1214 };
1215
1216 static x11_selection_type s_ptr[1];
1217
1218
1219 /*
1220  * Process a keypress event
1221  *
1222  * Also appears in "main-xaw.c".
1223  */
1224 static void react_keypress(XKeyEvent *xev)
1225 {
1226         int i, n, mc, ms, mo, mx;
1227
1228         uint ks1;
1229
1230         XKeyEvent *ev = (XKeyEvent*)(xev);
1231
1232         KeySym ks;
1233
1234         char buf[128];
1235         char msg[128];
1236
1237 #ifdef USE_XIM
1238         int valid_keysym = TRUE;
1239 #endif
1240
1241         /* Check for "normal" keypresses */
1242 #ifdef USE_XIM
1243         if(Focuswin && Focuswin->xic){
1244                 Status status;
1245                 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1246                 if(status == XBufferOverflow){
1247                         printf("Input is too long, and dropped\n");
1248                         return;
1249                 }
1250                 if(status != XLookupKeySym && status != XLookupBoth){
1251                         valid_keysym = FALSE;
1252                 }
1253         }else{
1254                 n = XLookupString(ev, buf, 125, &ks, NULL);
1255         }
1256 #else
1257         n = XLookupString(ev, buf, 125, &ks, NULL);
1258 #endif
1259
1260         /* Terminate */
1261         buf[n] = '\0';
1262
1263 #ifdef USE_XIM
1264         if(!valid_keysym){
1265                 /* Enqueue the normal key(s) */
1266                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1267
1268                 /* All done */
1269                 return;
1270         }
1271 #endif
1272
1273         /* Hack -- Ignore "modifier keys" */
1274         if (IsModifierKey(ks)) return;
1275
1276
1277         /* Hack -- convert into an unsigned int */
1278         ks1 = (uint)(ks);
1279
1280         /* Extract four "modifier flags" */
1281         mc = (ev->state & ControlMask) ? TRUE : FALSE;
1282         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1283         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1284         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1285
1286
1287         /* Normal keys with no modifiers */
1288         if (n && !mo && !mx && !IsSpecialKey(ks))
1289         {
1290                 /* Enqueue the normal key(s) */
1291                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1292
1293                 /* All done */
1294                 return;
1295         }
1296
1297
1298         /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1299         switch (ks1)
1300         {
1301                 case XK_Escape:
1302                 {
1303                         Term_keypress(ESCAPE);
1304                         return;
1305                 }
1306
1307                 case XK_Return:
1308                 {
1309                         Term_keypress('\r');
1310                         return;
1311                 }
1312
1313                 case XK_Tab:
1314                 {
1315                         Term_keypress('\t');
1316                         return;
1317                 }
1318
1319                 case XK_Delete:
1320                 {
1321                         Term_keypress(0x7f);
1322                         return;
1323                 }
1324                 case XK_BackSpace:
1325                 {
1326                         Term_keypress('\010');
1327                         return;
1328                 }
1329         }
1330
1331
1332         /* Hack -- Use the KeySym */
1333         if (ks)
1334         {
1335                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1336                         mc ? "N" : "", ms ? "S" : "",
1337                         mo ? "O" : "", mx ? "M" : "",
1338                         (unsigned long)(ks), 13);
1339         }
1340
1341         /* Hack -- Use the Keycode */
1342         else
1343         {
1344                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1345                         mc ? "N" : "", ms ? "S" : "",
1346                         mo ? "O" : "", mx ? "M" : "",
1347                         ev->keycode, 13);
1348         }
1349
1350         /* Enqueue the "macro trigger" string */
1351         for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1352
1353
1354         /* Hack -- auto-define macros as needed */
1355         if (n && (macro_find_exact(msg) < 0))
1356         {
1357                 /* Create a macro */
1358                 macro_add(msg, buf);
1359         }
1360 }
1361
1362
1363 /*
1364  * Find the square a particular pixel is part of.
1365  */
1366 static void pixel_to_square(int * const x, int * const y,
1367         const int ox, const int oy)
1368 {
1369         (*x) = (ox - Infowin->ox) / Infofnt->wid;
1370         (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1371 }
1372
1373 /*
1374  * Find the pixel at the top-left corner of a square.
1375  */
1376 static void square_to_pixel(int * const x, int * const y,
1377         const int ox, const int oy)
1378 {
1379         (*x) = ox * Infofnt->wid + Infowin->ox;
1380         (*y) = oy * Infofnt->hgt + Infowin->oy;
1381 }
1382
1383 /*
1384  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
1385  */
1386 static void sort_co_ord(co_ord *min, co_ord *max,
1387         const co_ord *b, const co_ord *a)
1388 {
1389         min->x = MIN(a->x, b->x);
1390         min->y = MIN(a->y, b->y);
1391         max->x = MAX(a->x, b->x);
1392         max->y = MAX(a->y, b->y);
1393 }
1394
1395 /*
1396  * Remove the selection by redrawing it.
1397  */
1398 static void mark_selection_clear(int x1, int y1, int x2, int y2)
1399 {
1400         Term_redraw_section(x1,y1,x2,y2);
1401 }
1402
1403 /*
1404  * Select an area by drawing a grey box around it.
1405  * NB. These two functions can cause flicker as the selection is modified,
1406  * as the game redraws the entire marked section.
1407  */
1408 static void mark_selection_mark(int x1, int y1, int x2, int y2)
1409 {
1410         square_to_pixel(&x1, &y1, x1, y1);
1411         square_to_pixel(&x2, &y2, x2, y2);
1412         XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
1413                 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1414 }
1415
1416 /*
1417  * Mark a selection by drawing boxes around it (for now).
1418  */
1419 static void mark_selection(void)
1420 {
1421         co_ord min, max;
1422         term *old = Term;
1423         bool draw = s_ptr->select;
1424         bool clear = s_ptr->drawn;
1425
1426         /* Open the correct term if necessary. */
1427         if (s_ptr->t != old) Term_activate(s_ptr->t);
1428
1429         if (clear)
1430         {
1431                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
1432                 mark_selection_clear(min.x, min.y, max.x, max.y);
1433         }
1434         if (draw)
1435         {
1436                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1437                 mark_selection_mark(min.x, min.y, max.x, max.y);
1438         }
1439
1440         /* Finish on the current term. */
1441         if (s_ptr->t != old) Term_activate(old);
1442
1443         s_ptr->old.x = s_ptr->cur.x;
1444         s_ptr->old.y = s_ptr->cur.y;
1445         s_ptr->drawn = s_ptr->select;
1446 }
1447
1448 /*
1449  * Forget a selection for one reason or another.
1450  */
1451 static void copy_x11_release(void)
1452 {
1453         /* Deselect the current selection. */
1454         s_ptr->select = FALSE;
1455
1456         /* Remove its graphical represesntation. */
1457         mark_selection();
1458 }
1459
1460 /*
1461  * Start to select some text on the screen.
1462  */
1463 static void copy_x11_start(int x, int y)
1464 {
1465         if (s_ptr->select) copy_x11_release();
1466
1467         /* Remember where the selection started. */
1468         s_ptr->t = Term;
1469         s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
1470         s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
1471 }
1472
1473 /*
1474  * Respond to movement of the mouse when selecting text.
1475  */
1476 static void copy_x11_cont(int x, int y, unsigned int buttons)
1477 {
1478         /* Use the nearest square within bounds if the mouse is outside. */
1479         x = MIN(MAX(x, 0), Term->wid-1);
1480         y = MIN(MAX(y, 0), Term->hgt-1);
1481
1482         /* The left mouse button isn't pressed. */
1483         if (~buttons & Button1Mask) return;
1484
1485         /* Not a selection in this window. */
1486         if (s_ptr->t != Term) return;
1487
1488         /* Not enough movement. */
1489         if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
1490
1491         /* Something is being selected. */
1492         s_ptr->select = TRUE;
1493
1494         /* Track the selection. */
1495         s_ptr->cur.x = x;
1496         s_ptr->cur.y = y;
1497
1498         /* Hack - display it inefficiently. */
1499         mark_selection();
1500 }
1501
1502 /*
1503  * Respond to release of the left mouse button by putting the selected text in
1504  * the primary buffer.
1505  */
1506 static void copy_x11_end(const Time time)
1507 {
1508         /* No selection. */
1509         if (!s_ptr->select) return;
1510
1511         /* Not a selection in this window. */
1512         if (s_ptr->t != Term) return;
1513
1514         /* Remember when the selection was finalised. */
1515         s_ptr->time = time;
1516
1517         /* Acquire the primary selection. */
1518         XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
1519         if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
1520         {
1521                 /* Failed to acquire the selection, so forget it. */
1522                 /* bell("Failed to acquire primary buffer."); */
1523                 s_ptr->select = FALSE;
1524                 mark_selection();
1525         }
1526 }
1527
1528
1529 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
1530
1531 /*
1532  * Set the required variable atoms at start-up to avoid errors later.
1533  */
1534 static void set_atoms(void)
1535 {
1536         xa_targets = XInternAtom(DPY, "TARGETS", False);
1537         xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
1538         xa_text = XInternAtom(DPY, "TEXT", False);
1539         xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
1540 }
1541
1542
1543 static Atom request_target = 0;
1544
1545 /*
1546  * Send a message to request that the PRIMARY buffer be sent here.
1547  */
1548 static void paste_x11_request(Atom target, const Time time)
1549 {
1550         /*
1551          * It's from some sample programs on the web.
1552          * What does it mean? -- XXX
1553          */
1554         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1555
1556         /* Check the owner. */
1557         if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
1558         {
1559                 /* No selection. */
1560                 /* bell("No selection found."); */
1561                 return;
1562         }
1563
1564         request_target = target;
1565     
1566         /* Request the event */
1567         XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
1568 }
1569
1570
1571 /*
1572  * Add the contents of the PRIMARY buffer to the input queue.
1573  *
1574  * Hack - This doesn't use the "time" of the event, and so accepts anything a
1575  * client tries to send it.
1576  */
1577 static void paste_x11_accept(const XSelectionEvent *ptr)
1578 {
1579         unsigned long left;
1580         const long offset = 0;
1581         const long length = 32000;
1582         XTextProperty xtextproperty;
1583         errr err = 0;
1584
1585         /*
1586          * It's from some sample programs on the web.
1587          * What does it mean? -- XXX
1588          */
1589         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1590
1591
1592         /* Failure. */
1593         if (ptr->property == None)
1594         {
1595                 if (request_target == xa_compound_text)
1596                 {
1597                         /* Re-request as STRING */
1598                         paste_x11_request(XA_STRING, ptr->time);
1599                 }
1600                 else
1601                 {
1602                         request_target = 0;
1603                         plog("Paste failure (remote client could not send).");
1604                 }
1605                 return;
1606         }
1607
1608         if (ptr->selection != XA_PRIMARY)
1609         {
1610                 plog("Paste failure (remote client did not send primary selection).");
1611                 return;
1612         }
1613
1614         if (ptr->target != request_target)
1615         {
1616                 plog("Paste failure (selection in unknown format).");
1617                 return;
1618         }
1619
1620         /* Get text */
1621         if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
1622                                length, TRUE, request_target,
1623                                &xtextproperty.encoding,
1624                                &xtextproperty.format,
1625                                &xtextproperty.nitems,
1626                                &left,
1627                                &xtextproperty.value)
1628             != Success)
1629         {
1630                 /* Failure */
1631                 return;
1632         }
1633
1634         if (request_target == xa_compound_text)
1635         {
1636                 char **list;
1637                 int count;
1638                 
1639                 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
1640
1641                 if (list)
1642                 {
1643                         int i;
1644
1645                         for (i = 0; i < count; i++)
1646                         {
1647                                 /* Paste the text. */
1648                                 err = type_string(list[i], 0);
1649
1650                                 if (err) break;
1651                         }
1652
1653                         /* Free the string */
1654                         XFreeStringList(list);
1655                 }
1656         }
1657         else /* if (request_target == XA_STRING) */
1658         {
1659                 /* Paste the text. */
1660                 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
1661         }
1662
1663         /* Free the data pasted. */
1664         XFree(xtextproperty.value); 
1665
1666         /* No room. */
1667         if (err)
1668         {
1669                 plog("Paste failure (too much text selected).");
1670         }
1671 }
1672
1673
1674 /*
1675  * Add a character to a string in preparation for sending it to another
1676  * client as a STRING.
1677  * This doesn't change anything, as clients tend not to have difficulty in
1678  * receiving this format (although the standard specifies a restricted set).
1679  * Strings do not have a colour.
1680  */
1681 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
1682 {
1683         char buf[1024];
1684         char *list[1000];
1685         co_ord max, min;
1686         TERM_LEN x,y;
1687         int l,n;
1688         TERM_COLOR a;
1689         char c;
1690
1691         /* Too old, or incorrect call. */
1692         if (rq->time < s_ptr->time) return FALSE;
1693
1694         /* Work out which way around to paste. */
1695         sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1696
1697         /* Paranoia. */
1698         if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
1699         {
1700                 /* bell("Someone stole my selection!"); */
1701                 return FALSE;
1702         }
1703
1704         /* Delete the old value of the property. */
1705         XDeleteProperty(DPY, rq->requestor, rq->property);
1706
1707         for (n = 0, y = 0; y < Term->hgt; y++)
1708         {
1709 #ifdef JP
1710                 int kanji = 0;
1711 #endif
1712                 if (y < min.y) continue;
1713                 if (y > max.y) break;
1714
1715                 for (l = 0, x = 0; x < Term->wid; x++)
1716                 {
1717 #ifdef JP
1718                         if (x > max.x) break;
1719
1720                         /* Find the character. */
1721                         Term_what(x, y, &a, &c);
1722
1723                         if (1 == kanji) kanji = 2;
1724                         else if (iskanji(c)) kanji = 1;
1725                         else kanji = 0;
1726
1727                         if (x < min.x) continue;
1728
1729                         /*
1730                          * A single kanji character was divided in two...
1731                          * Delete the garbage.
1732                          */
1733                         if ((2 == kanji && x == min.x) ||
1734                             (1 == kanji && x == max.x))
1735                                 c = ' ';
1736 #else
1737                         if (x > max.x) break;
1738                         if (x < min.x) continue;
1739
1740                         /* Find the character. */
1741                         Term_what(x, y, &a, &c);
1742 #endif
1743
1744                         /* Add it. */
1745                         buf[l] = c;
1746                         l++;
1747                 }
1748
1749                 /* Ignore trailing spaces */
1750                 while (buf[l-1] == ' ') l--;
1751
1752                 /* Terminate all line unless it's single line. */
1753                 if (min.y != max.y)
1754                 {
1755                         buf[l] = '\n';
1756                         l++;
1757                 }
1758
1759                 /* End of string */
1760                 buf[l] = '\0';
1761
1762                 list[n++] = (char *)string_make(buf);
1763         }
1764
1765         /* End of the list */
1766         list[n] = NULL;
1767
1768
1769         if (rq->target == XA_STRING)
1770         {
1771                 for (n = 0; list[n]; n++)
1772                 {
1773                         /* Send the (non-empty) string. */
1774                         XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
1775                                         PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
1776                 }
1777         }
1778
1779         else if (rq->target == xa_text || 
1780                  rq->target == xa_compound_text)
1781         {
1782                 XTextProperty text_prop;
1783                 XICCEncodingStyle style;
1784
1785                 if (rq->target == xa_text)
1786                         style = XStdICCTextStyle;
1787                 else /* if (rq->target == xa_compound_text) */
1788                         style = XCompoundTextStyle;
1789
1790                 if (Success ==
1791                     XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
1792                 {
1793                         /* Send the compound text */
1794                         XChangeProperty(DPY,
1795                                         rq->requestor,
1796                                         rq->property,
1797                                         text_prop.encoding,
1798                                         text_prop.format,
1799                                         PropModeAppend,
1800                                         text_prop.value,
1801                                         text_prop.nitems);
1802                                 
1803                         /* Free the data. */
1804                         XFree(text_prop.value);
1805                 }
1806         }
1807
1808         /* Free the list of strings */
1809         for (n = 0; list[n]; n++)
1810         {
1811                 string_free(list[n]);
1812         }
1813
1814         return TRUE;
1815 }
1816
1817 /*
1818  * Send some text requested by another X client.
1819  */
1820 static void paste_x11_send(XSelectionRequestEvent *rq)
1821 {
1822         XEvent event;
1823         XSelectionEvent *ptr = &(event.xselection);
1824
1825         /* Set the event parameters. */
1826         ptr->type = SelectionNotify;
1827         ptr->property = rq->property;
1828         ptr->display = rq->display;
1829         ptr->requestor = rq->requestor;
1830         ptr->selection = rq->selection;
1831         ptr->target = rq->target;
1832         ptr->time = rq->time;
1833
1834         /* Paste the appropriate information for each target type.
1835          * Note that this currently rejects MULTIPLE targets.
1836          */
1837
1838         if (rq->target == XA_STRING ||
1839             rq->target == xa_text ||
1840             rq->target == xa_compound_text)
1841         {
1842                 if (!paste_x11_send_text(rq))
1843                         ptr->property = None;
1844         }
1845         else if (rq->target == xa_targets)
1846         {
1847                 Atom target_list[4];
1848                 target_list[0] = XA_STRING;
1849                 target_list[1] = xa_text;
1850                 target_list[2] = xa_compound_text;
1851                 target_list[3] = xa_targets;
1852                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1853                         (8 * sizeof(target_list[0])), PropModeReplace,
1854                         (unsigned char *)target_list,
1855                         (sizeof(target_list) / sizeof(target_list[0])));
1856         }
1857         else if (rq->target == xa_timestamp)
1858         {
1859                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1860                         (8 * sizeof(Time)), PropModeReplace,
1861                         (unsigned char *)s_ptr->time, 1);
1862         }
1863         else
1864         {
1865                 ptr->property = None;
1866         }
1867
1868         /* Send whatever event we're left with. */
1869         XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
1870 }
1871
1872
1873 /*
1874  * Handle various events conditional on presses of a mouse button.
1875  */
1876 static void handle_button(Time time, int x, int y, int button,
1877         bool press)
1878 {
1879         /* The co-ordinates are only used in Angband format. */
1880         pixel_to_square(&x, &y, x, y);
1881
1882         if (press && button == 1) copy_x11_start(x, y);
1883         if (!press && button == 1) copy_x11_end(time);
1884         if (!press && button == 2) paste_x11_request(xa_compound_text, time);
1885 }
1886
1887
1888 /*
1889  * Process events
1890  */
1891 static errr CheckEvent(bool wait)
1892 {
1893         term_data *old_td = (term_data*)(Term->data);
1894
1895         XEvent xev_body, *xev = &xev_body;
1896
1897         term_data *td = NULL;
1898         infowin *iwin = NULL;
1899
1900         int i;
1901
1902 #ifdef USE_XIM
1903  redo_checkevent:
1904 #endif
1905
1906         /* Do not wait unless requested */
1907         if (!wait && !XPending(Metadpy->dpy)) return (1);
1908
1909         /*
1910          * Hack - redraw the selection, if needed.
1911          * This doesn't actually check that one of its squares was drawn to,
1912          * only that this may have happened.
1913          */
1914         if (s_ptr->select && !s_ptr->drawn) mark_selection();
1915
1916         /* Load the Event */
1917         XNextEvent(Metadpy->dpy, xev);
1918
1919 #ifdef USE_XIM
1920         if (XFilterEvent(xev, xev->xany.window)
1921         {
1922                 goto redo_checkevent;
1923         }
1924 #endif
1925
1926         /* Notice new keymaps */
1927         if (xev->type == MappingNotify)
1928         {
1929                 XRefreshKeyboardMapping(&xev->xmapping);
1930                 return 0;
1931         }
1932
1933
1934         /* Scan the windows */
1935         for (i = 0; i < MAX_TERM_DATA; i++)
1936         {
1937                 if (!data[i].win) continue;
1938                 if (xev->xany.window == data[i].win->win)
1939                 {
1940                         td = &data[i];
1941                         iwin = td->win;
1942                         break;
1943                 }
1944         }
1945
1946         /* Unknown window */
1947         if (!td || !iwin) return (0);
1948
1949
1950         /* Hack -- activate the Term */
1951         Term_activate(&td->t);
1952
1953         /* Hack -- activate the window */
1954         Infowin_set(iwin);
1955
1956
1957         /* Switch on the Type */
1958         switch (xev->type)
1959         {
1960                 case ButtonPress:
1961                 case ButtonRelease:
1962                 {
1963                         bool press = (xev->type == ButtonPress);
1964
1965                         /* Where is the mouse */
1966                         int x = xev->xbutton.x;
1967                         int y = xev->xbutton.y;
1968
1969                         int z;
1970
1971                         /* Which button is involved */
1972                         if (xev->xbutton.button == Button1) z = 1;
1973                         else if (xev->xbutton.button == Button2) z = 2;
1974                         else if (xev->xbutton.button == Button3) z = 3;
1975                         else if (xev->xbutton.button == Button4) z = 4;
1976                         else if (xev->xbutton.button == Button5) z = 5;
1977                         else z = 0;
1978
1979                         /* XXX Handle */
1980                         handle_button(xev->xbutton.time, x, y, z, press);
1981
1982                         break;
1983                 }
1984
1985                 case EnterNotify:
1986                 case LeaveNotify:
1987                 {
1988                         /* XXX Handle */
1989
1990                         break;
1991                 }
1992
1993                 case MotionNotify:
1994                 {
1995                         /* Where is the mouse */
1996                         int x = xev->xmotion.x;
1997                         int y = xev->xmotion.y;
1998                         unsigned int z = xev->xmotion.state;
1999
2000                         /* Convert to co-ordinates Angband understands. */
2001                         pixel_to_square(&x, &y, x, y);
2002
2003                         /* Highlight the current square, if appropriate. */
2004                         /* highlight_square(window, y, x); */
2005
2006                         /* Alter the selection if appropriate. */
2007                         copy_x11_cont(x, y, z);
2008
2009                         /* XXX Handle */
2010
2011                         break;
2012                 }
2013
2014                 case SelectionNotify:
2015                 {
2016                         paste_x11_accept(&(xev->xselection));
2017                         break;
2018                 }
2019
2020                 case SelectionRequest:
2021                 {
2022                         paste_x11_send(&(xev->xselectionrequest));
2023                         break;
2024                 }
2025
2026                 case SelectionClear:
2027                 {
2028                         s_ptr->select = FALSE;
2029                         mark_selection();
2030                         break;
2031                 }
2032
2033                 case KeyRelease:
2034                 {
2035                         /* Nothing */
2036                         break;
2037                 }
2038
2039                 case KeyPress:
2040                 {
2041                         /* Hack -- use "old" term */
2042                         Term_activate(&old_td->t);
2043
2044                         /* Process the key */
2045                         react_keypress(&(xev->xkey));
2046
2047                         break;
2048                 }
2049
2050                 case Expose:
2051                 {
2052                         int x1, x2, y1, y2;
2053                         
2054                         /* Ignore "extra" exposes */
2055                         /*if (xev->xexpose.count) break;*/
2056
2057                         /* Clear the window */
2058                         /*Infowin_wipe();*/
2059                         
2060                         x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
2061                         x2 = (xev->xexpose.x + xev->xexpose.width -
2062                                  Infowin->ox)/Infofnt->wid;
2063                         
2064                         y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
2065                         y2 = (xev->xexpose.y + xev->xexpose.height -
2066                                  Infowin->oy)/Infofnt->hgt;
2067                         
2068                         Term_redraw_section(x1, y1, x2, y2);
2069
2070                         /* Redraw */
2071                         /*Term_redraw();*/
2072
2073                         break;
2074                 }
2075
2076                 case MapNotify:
2077                 {
2078                         Infowin->mapped = 1;
2079                         Term->mapped_flag = TRUE;
2080                         break;
2081                 }
2082
2083                 case UnmapNotify:
2084                 {
2085                         Infowin->mapped = 0;
2086                         Term->mapped_flag = FALSE;
2087                         break;
2088                 }
2089
2090                 /* Move and/or Resize */
2091                 case ConfigureNotify:
2092                 {
2093                         int cols, rows, wid, hgt;
2094
2095                         int ox = Infowin->ox;
2096                         int oy = Infowin->oy;
2097
2098                         /* Save the new Window Parms */
2099                         Infowin->x = xev->xconfigure.x;
2100                         Infowin->y = xev->xconfigure.y;
2101                         Infowin->w = xev->xconfigure.width;
2102                         Infowin->h = xev->xconfigure.height;
2103
2104                         /* Determine "proper" number of rows/cols */
2105                         cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2106                         rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2107
2108                         /* Hack -- minimal size */
2109                         if (cols < 1) cols = 1;
2110                         if (rows < 1) rows = 1;
2111
2112                         if (td == &data[0])
2113                         {
2114                                 /* Hack the main window must be at least 80x24 */
2115                                 if (cols < 80) cols = 80;
2116                                 if (rows < 24) rows = 24;
2117                         }
2118
2119                         /* Desired size of window */
2120                         wid = cols * td->fnt->wid + (ox + ox);
2121                         hgt = rows * td->fnt->hgt + (oy + oy);
2122
2123                         /* Resize the Term (if needed) */
2124                         Term_resize(cols, rows);
2125
2126                         /* Resize the windows if any "change" is needed */
2127                         if ((Infowin->w != wid) || (Infowin->h != hgt))
2128                         {
2129                                 /* Resize window */
2130                                 Infowin_set(td->win);
2131                                 Infowin_resize(wid, hgt);
2132                         }
2133
2134                         break;
2135                 }
2136 #ifdef USE_XIM
2137                 case FocusIn:
2138                 {
2139                         if(iwin->xic){
2140                                 XSetICFocus(iwin->xic);
2141                         }
2142                         Focuswin = iwin;
2143                         break;
2144                 }
2145                 case FocusOut:
2146                 {
2147                         if(iwin->xic){
2148                                 XUnsetICFocus(iwin->xic);
2149                         }
2150                         /* Focuswin = NULL;*/
2151                         break;
2152                 }
2153 #endif
2154         }
2155
2156
2157         /* Hack -- Activate the old term */
2158         Term_activate(&old_td->t);
2159
2160         /* Hack -- Activate the proper window */
2161         Infowin_set(old_td->win);
2162
2163
2164         /* Success */
2165         return (0);
2166 }
2167
2168
2169  /*
2170   * Standard sound names
2171   */
2172 static const concptr angband_sound_name[SOUND_MAX] =
2173 {
2174         "dummy",
2175         "hit",
2176         "miss",
2177         "flee",
2178         "drop",
2179         "kill",
2180         "level",
2181         "death",
2182         "study",
2183         "teleport",
2184         "shoot",
2185         "quaff",
2186         "zap",
2187         "walk",
2188         "tpother",
2189         "hitwall",
2190         "eat",
2191         "store1",
2192         "store2",
2193         "store3",
2194         "store4",
2195         "dig",
2196         "opendoor",
2197         "shutdoor",
2198         "tplevel",
2199         "scroll",
2200         "buy",
2201         "sell",
2202         "warn",
2203         "rocket",
2204         "n_kill",
2205         "u_kill",
2206         "quest",
2207         "heal",
2208         "x_heal",
2209         "bite",
2210         "claw",
2211         "m_spell",
2212         "summon",
2213         "breath",
2214         "ball",
2215         "m_heal",
2216         "atkspell",
2217         "evil",
2218         "touch",
2219         "sting",
2220         "crush",
2221         "slime",
2222         "wail",
2223         "winner",
2224         "fire",
2225         "acid",
2226         "elec",
2227         "cold",
2228         "illegal",
2229         "fail",
2230         "wakeup",
2231         "invuln",
2232         "fall",
2233         "pain",
2234         "destitem",
2235         "moan",
2236         "show",
2237         "unused",
2238         "explode",
2239         "glass",
2240         "reflect",
2241 };
2242
2243 /*
2244  * An array of sound file names
2245  */
2246 static concptr sound_file[SOUND_MAX];
2247
2248 /*
2249  * Check for existance of a file
2250  */
2251 static bool check_file(concptr s)
2252 {
2253         FILE *fff;
2254
2255         fff = fopen(s, "r");
2256         if (!fff) return (FALSE);
2257         
2258         fclose(fff);
2259         return (TRUE);
2260 }
2261
2262 /*
2263  * Initialize sound
2264  */
2265 static void init_sound(void)
2266 {
2267         int i;
2268         char wav[128];
2269         char buf[1024];
2270         char dir_xtra_sound[1024];
2271                 
2272         /* Build the "sound" path */
2273         path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
2274                 
2275         /* Prepare the sounds */
2276         for (i = 1; i < SOUND_MAX; i++)
2277         {
2278                 /* Extract name of sound file */
2279                 sprintf(wav, "%s.wav", angband_sound_name[i]);
2280                 
2281                 /* Access the sound */
2282                 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
2283                 
2284                 /* Save the sound filename, if it exists */
2285                 if (check_file(buf)) sound_file[i] = string_make(buf);
2286         }
2287         use_sound = TRUE;
2288         return;
2289 }
2290
2291 /*
2292  * Hack -- make a sound
2293  */
2294 static errr Term_xtra_x11_sound(int v)
2295 {
2296         char buf[1024];
2297         
2298         /* Sound disabled */
2299         if (!use_sound) return (1);
2300         
2301         /* Illegal sound */
2302         if ((v < 0) || (v >= SOUND_MAX)) return (1);
2303         
2304         /* Unknown sound */
2305         if (!sound_file[v]) return (1);
2306         
2307         sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
2308         
2309         return (system(buf) < 0);
2310         
2311 }
2312
2313
2314 /*
2315  * Handle "activation" of a term
2316  */
2317 static errr Term_xtra_x11_level(int v)
2318 {
2319         term_data *td = (term_data*)(Term->data);
2320
2321         /* Handle "activate" */
2322         if (v)
2323         {
2324                 /* Activate the window */
2325                 Infowin_set(td->win);
2326
2327                 /* Activate the font */
2328                 Infofnt_set(td->fnt);
2329         }
2330
2331         /* Success */
2332         return (0);
2333 }
2334
2335
2336 /*
2337  * React to changes
2338  */
2339 static errr Term_xtra_x11_react(void)
2340 {
2341         int i;
2342         
2343         if (Metadpy->color)
2344         {
2345                 /* Check the colors */
2346                 for (i = 0; i < 256; i++)
2347                 {
2348                         if ((color_table[i][0] != angband_color_table[i][0]) ||
2349                             (color_table[i][1] != angband_color_table[i][1]) ||
2350                             (color_table[i][2] != angband_color_table[i][2]) ||
2351                             (color_table[i][3] != angband_color_table[i][3]))
2352                         {
2353                                 Pixell pixel;
2354
2355                                 /* Save new values */
2356                                 color_table[i][0] = angband_color_table[i][0];
2357                                 color_table[i][1] = angband_color_table[i][1];
2358                                 color_table[i][2] = angband_color_table[i][2];
2359                                 color_table[i][3] = angband_color_table[i][3];
2360
2361                                 /* Create pixel */
2362                                 pixel = create_pixel(Metadpy->dpy,
2363                                                      color_table[i][1],
2364                                                      color_table[i][2],
2365                                                      color_table[i][3]);
2366
2367                                 /* Change the foreground */
2368                                 Infoclr_set(clr[i]);
2369                                 Infoclr_change_fg(pixel);
2370                         }
2371                 }
2372         }
2373
2374         /* Success */
2375         return (0);
2376 }
2377
2378
2379 /*
2380  * Handle a "special request"
2381  */
2382 static errr Term_xtra_x11(int n, int v)
2383 {
2384         /* Handle a subset of the legal requests */
2385         switch (n)
2386         {
2387                 /* Make a noise */
2388                 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
2389
2390                 /* Make a special sound */
2391                 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
2392
2393                 /* Flush the output XXX XXX */
2394                 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
2395
2396                 /* Process random events XXX */
2397                 case TERM_XTRA_BORED: return (CheckEvent(0));
2398
2399                 /* Process Events XXX */
2400                 case TERM_XTRA_EVENT: return (CheckEvent(v));
2401
2402                 /* Flush the events XXX */
2403                 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
2404
2405                 /* Handle change in the "level" */
2406                 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
2407
2408                 /* Clear the screen */
2409                 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
2410
2411                 /* Delay for some milliseconds */
2412                 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
2413
2414                 /* React to changes */
2415                 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
2416         }
2417
2418         /* Unknown */
2419         return (1);
2420 }
2421
2422
2423 /*
2424  * Draw the cursor as an inverted rectangle.
2425  *
2426  * Consider a rectangular outline like "main-mac.c".  XXX XXX
2427  */
2428 static errr Term_curs_x11(int x, int y)
2429 {
2430         if (use_graphics)
2431         {
2432                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2433                                x * Infofnt->wid + Infowin->ox,
2434                                y * Infofnt->hgt + Infowin->oy,
2435                                Infofnt->wid - 1, Infofnt->hgt - 1);
2436                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2437                                x * Infofnt->wid + Infowin->ox + 1,
2438                                y * Infofnt->hgt + Infowin->oy + 1,
2439                                Infofnt->wid - 3, Infofnt->hgt - 3);
2440         }
2441         else
2442         {
2443                 /* Draw the cursor */
2444                 Infoclr_set(xor);
2445
2446                 /* Hilite the cursor character */
2447                 Infofnt_text_non(x, y, " ", 1);
2448         }
2449
2450         /* Success */
2451         return (0);
2452 }
2453
2454
2455 /*
2456  * Draw the double width cursor
2457  */
2458 static errr Term_bigcurs_x11(int x, int y)
2459 {
2460         if (use_graphics)
2461         {
2462                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2463                                x * Infofnt->wid + Infowin->ox,
2464                                y * Infofnt->hgt + Infowin->oy,
2465                                Infofnt->twid - 1, Infofnt->hgt - 1);
2466                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2467                                x * Infofnt->wid + Infowin->ox + 1,
2468                                y * Infofnt->hgt + Infowin->oy + 1,
2469                                Infofnt->twid - 3, Infofnt->hgt - 3);
2470         }
2471         else
2472         {
2473                 /* Draw the cursor */
2474                 Infoclr_set(xor);
2475
2476                 /* Hilite the cursor character */
2477                 Infofnt_text_non(x, y, "  ", 2);
2478         }
2479         /* Success */
2480         return (0);
2481 }
2482
2483
2484 /*
2485  * Erase some characters.
2486  */
2487 static errr Term_wipe_x11(int x, int y, int n)
2488 {
2489         /* Erase (use black) */
2490         Infoclr_set(clr[TERM_DARK]);
2491
2492         /* Mega-Hack -- Erase some space */
2493         Infofnt_text_non(x, y, "", n);
2494
2495         /* Redraw the selection if any, as it may have been obscured. (later) */
2496         s_ptr->drawn = FALSE;
2497
2498         /* Success */
2499         return (0);
2500 }
2501
2502
2503 /*
2504  * Draw some textual characters.
2505  */
2506 static errr Term_text_x11(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
2507 {
2508         /* Draw the text */
2509         Infoclr_set(clr[a]);
2510
2511         /* Draw the text */
2512         Infofnt_text_std(x, y, s, n);
2513
2514         /* Redraw the selection if any, as it may have been obscured. (later) */
2515         s_ptr->drawn = FALSE;
2516
2517         /* Success */
2518         return (0);
2519 }
2520
2521
2522 /*
2523  * Draw some graphical characters.
2524  */
2525 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)
2526 {
2527         int i, x1, y1;
2528
2529         TERM_COLOR a;
2530         char c;
2531
2532         TERM_COLOR ta;
2533         char tc;
2534
2535         int x2, y2;
2536         int k,l;
2537
2538         unsigned long pixel, blank;
2539
2540         term_data *td = (term_data*)(Term->data);
2541
2542         y *= Infofnt->hgt;
2543         x *= Infofnt->wid;
2544
2545         /* Add in affect of window boundaries */
2546         y += Infowin->oy;
2547         x += Infowin->ox;
2548
2549         for (i = 0; i < n; ++i, x += td->fnt->wid)
2550         {
2551                 a = *ap++;
2552                 c = *cp++;
2553
2554                 /* For extra speed - cache these values */
2555                 x1 = (c&0x7F) * td->fnt->twid;
2556                 y1 = (a&0x7F) * td->fnt->hgt;
2557
2558                 /* Illegal tile index */
2559                 if (td->tiles->width < x1 + td->fnt->wid ||
2560                     td->tiles->height < y1 + td->fnt->hgt)
2561                 {
2562                         /* Draw black square */
2563                         XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc,
2564                                        x, y, 
2565                                        td->fnt->twid, td->fnt->hgt);
2566
2567                         /* Skip drawing tile */
2568                         continue;
2569                 }
2570
2571                 ta = *tap++;
2572                 tc = *tcp++;
2573
2574                 /* For extra speed - cache these values */
2575                 x2 = (tc&0x7F) * td->fnt->twid;
2576                 y2 = (ta&0x7F) * td->fnt->hgt;
2577                 
2578                 /* Optimise the common case */
2579                 if (((x1 == x2) && (y1 == y2)) ||
2580                     !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
2581                     td->tiles->width < x2 + td->fnt->wid ||
2582                     td->tiles->height < y2 + td->fnt->hgt)
2583                 {
2584                         /* Draw object / terrain */
2585                         XPutImage(Metadpy->dpy, td->win->win,
2586                                 clr[0]->gc,
2587                                 td->tiles,
2588                                 x1, y1,
2589                                 x, y,
2590                                 td->fnt->twid, td->fnt->hgt);   
2591                 }
2592                 else
2593                 {
2594
2595                         /* Mega Hack^2 - assume the top left corner is "black" */
2596                         blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
2597
2598                         for (k = 0; k < td->fnt->twid; k++)
2599                         {
2600                                 for (l = 0; l < td->fnt->hgt; l++)
2601                                 {
2602                                         /* If mask set... */
2603                                         if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
2604                                         {
2605                                                 /* Output from the terrain */
2606                                                 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
2607                                         }
2608                                         
2609                                         /* Store into the temp storage. */
2610                                         XPutPixel(td->TmpImage, k, l, pixel);
2611                                 }
2612                         }
2613
2614
2615                         /* Draw to screen */
2616
2617                         XPutImage(Metadpy->dpy, td->win->win,
2618                               clr[0]->gc,
2619                              td->TmpImage,
2620                              0, 0, x, y,
2621                              td->fnt->twid, td->fnt->hgt);
2622                 }
2623         }
2624
2625         /* Redraw the selection if any, as it may have been obscured. (later) */
2626         s_ptr->drawn = FALSE;
2627
2628         /* Success */
2629         return (0);
2630 }
2631
2632 #ifdef USE_XIM
2633 static void IMDestroyCallback(XIM, XPointer, XPointer);
2634
2635 static void
2636 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
2637 {
2638         XIM xim;
2639         XIMCallback ximcallback;
2640         XIMStyles *xim_styles = NULL;
2641         int i;
2642
2643         /* Unused */
2644         (void)unused1;
2645         (void)unused2;
2646
2647         xim = XOpenIM(display, NULL, NULL, NULL);
2648         if(!xim){
2649                 printf("can't open IM\n");
2650                 return;
2651         }
2652
2653         /* initialize destroy callback */
2654         ximcallback.callback = IMDestroyCallback;
2655         ximcallback.client_data = NULL;
2656         XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
2657
2658         /* set style (only "Root" is supported yet...) */
2659         XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
2660         for (i = 0; i < xim_styles->count_styles; i++){
2661                 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
2662         }
2663         if(i >= xim_styles->count_styles){
2664                 printf("Sorry, your IM does not support 'Root' preedit style...\n");
2665                 XCloseIM(xim);
2666                 return;
2667         }
2668         XFree(xim_styles);
2669
2670         Metadpy->xim = xim;
2671
2672         for (i = 0; i < MAX_TERM_DATA; i++)
2673         {
2674                 infowin *iwin = data[i].win;
2675                 if (!iwin) continue;
2676                 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
2677                 if(!iwin->xic){
2678                         printf("Can't create input context for Term%d\n", i);
2679                         continue;
2680                 }
2681                 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL){
2682 /*                      printf("Can't get XNFilterEvents\n"); */
2683                         iwin->xic_mask = 0L;
2684                 }
2685                 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
2686         }
2687
2688         return;
2689 }
2690
2691 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
2692 {
2693         int i;
2694
2695         /* Unused */
2696         (void)xim;
2697         (void)client_data;
2698
2699         if (call_data == NULL){
2700                 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
2701         }
2702
2703         for(i = 0; i < MAX_TERM_DATA; i++)
2704         {
2705                 infowin *iwin = data[i].win;
2706                 if(!iwin) continue;
2707                 if(iwin->xic_mask){
2708                         XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
2709                         iwin->xic_mask = 0L;
2710                 }
2711                 iwin->xic = NULL;
2712         }
2713
2714         Metadpy->xim = NULL;
2715 }
2716 #endif
2717
2718 /*
2719  * Initialize a term_data
2720  */
2721 static errr term_data_init(term_data *td, int i)
2722 {
2723         term *t = &td->t;
2724
2725         concptr name = angband_term_name[i];
2726
2727         concptr font;
2728         int x = 0;
2729         int y = 0;
2730
2731         int cols = 80;
2732         int rows = 24;
2733
2734         int ox = 1;
2735         int oy = 1;
2736
2737         int wid, hgt, num;
2738
2739         char buf[80];
2740
2741         concptr str;
2742
2743         int val;
2744
2745         XClassHint *ch;
2746
2747         char res_name[20];
2748         char res_class[20];
2749
2750         XSizeHints *sh;
2751 #ifdef USE_XIM
2752         XWMHints *wh;
2753 #endif
2754
2755         /* Window specific font name */
2756         sprintf(buf, "ANGBAND_X11_FONT_%d", i);
2757
2758         /* Check environment for that font */
2759         font = getenv(buf);
2760
2761         /* Check environment for "base" font */
2762         if (!font) font = getenv("ANGBAND_X11_FONT");
2763
2764         /* No environment variables, use default font */
2765         if (!font)
2766         {
2767                 switch (i)
2768                 {
2769                         case 0:
2770                         {
2771                                 font = DEFAULT_X11_FONT_0;
2772                         }
2773                         break;
2774                         case 1:
2775                         {
2776                                 font = DEFAULT_X11_FONT_1;
2777                         }
2778                         break;
2779                         case 2:
2780                         {
2781                                 font = DEFAULT_X11_FONT_2;
2782                         }
2783                         break;
2784                         case 3:
2785                         {
2786                                 font = DEFAULT_X11_FONT_3;
2787                         }
2788                         break;
2789                         case 4:
2790                         {
2791                                 font = DEFAULT_X11_FONT_4;
2792                         }
2793                         break;
2794                         case 5:
2795                         {
2796                                 font = DEFAULT_X11_FONT_5;
2797                         }
2798                         break;
2799                         case 6:
2800                         {
2801                                 font = DEFAULT_X11_FONT_6;
2802                         }
2803                         break;
2804                         case 7:
2805                         {
2806                                 font = DEFAULT_X11_FONT_7;
2807                         }
2808                         break;
2809                         default:
2810                         {
2811                                 font = DEFAULT_X11_FONT;
2812                         }
2813                 }
2814         }
2815
2816         /* Window specific location (x) */
2817         sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
2818         str = getenv(buf);
2819         x = (str != NULL) ? atoi(str) : -1;
2820
2821         /* Window specific location (y) */
2822         sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
2823         str = getenv(buf);
2824         y = (str != NULL) ? atoi(str) : -1;
2825
2826
2827         /* Window specific cols */
2828         sprintf(buf, "ANGBAND_X11_COLS_%d", i);
2829         str = getenv(buf);
2830         val = (str != NULL) ? atoi(str) : -1;
2831         if (val > 0) cols = val;
2832
2833         /* Window specific rows */
2834         sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
2835         str = getenv(buf);
2836         val = (str != NULL) ? atoi(str) : -1;
2837         if (val > 0) rows = val;
2838
2839         /* Hack the main window must be at least 80x24 */
2840         if (!i)
2841         {
2842                 if (cols < 80) cols = 80;
2843                 if (rows < 24) rows = 24;
2844         }
2845
2846         /* Window specific inner border offset (ox) */
2847         sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
2848         str = getenv(buf);
2849         val = (str != NULL) ? atoi(str) : -1;
2850         if (val > 0) ox = val;
2851
2852         /* Window specific inner border offset (oy) */
2853         sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
2854         str = getenv(buf);
2855         val = (str != NULL) ? atoi(str) : -1;
2856         if (val > 0) oy = val;
2857
2858
2859         /* Prepare the standard font */
2860         MAKE(td->fnt, infofnt);
2861         Infofnt_set(td->fnt);
2862         Infofnt_init_data(font);
2863
2864         /* Hack -- key buffer size */
2865         num = ((i == 0) ? 1024 : 16);
2866
2867         /* Assume full size windows */
2868         wid = cols * td->fnt->wid + (ox + ox);
2869         hgt = rows * td->fnt->hgt + (oy + oy);
2870
2871         /* Create a top-window */
2872         MAKE(td->win, infowin);
2873         Infowin_set(td->win);
2874         Infowin_init_top(x, y, wid, hgt, 0,
2875                          Metadpy->fg, Metadpy->bg);
2876
2877         /* Ask for certain events */
2878 #if defined(USE_XIM)
2879         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
2880 #else
2881         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
2882 #endif
2883
2884         /* Set the window name */
2885         Infowin_set_name(name);
2886
2887         /* Save the inner border */
2888         Infowin->ox = ox;
2889         Infowin->oy = oy;
2890
2891         /* Make Class Hints */
2892         ch = XAllocClassHint();
2893
2894         if (ch == NULL) quit("XAllocClassHint failed");
2895
2896         strcpy(res_name, name);
2897         res_name[0] = FORCELOWER(res_name[0]);
2898         ch->res_name = res_name;
2899
2900         strcpy(res_class, "Angband");
2901         ch->res_class = res_class;
2902
2903         XSetClassHint(Metadpy->dpy, Infowin->win, ch);
2904
2905         /* Make Size Hints */
2906         sh = XAllocSizeHints();
2907
2908         /* Oops */
2909         if (sh == NULL) quit("XAllocSizeHints failed");
2910
2911         /* Main window has a differing minimum size */
2912         if (i == 0)
2913         {
2914                 /* Main window min size is 80x24 */
2915                 sh->flags = PMinSize | PMaxSize;
2916                 sh->min_width = 80 * td->fnt->wid + (ox + ox);
2917                 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
2918                 sh->max_width = 255 * td->fnt->wid + (ox + ox);
2919                 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
2920         }
2921
2922         /* Other windows can be shrunk to 1x1 */
2923         else
2924         {
2925                 /* Other windows */
2926                 sh->flags = PMinSize | PMaxSize;
2927                 sh->min_width = td->fnt->wid + (ox + ox);
2928                 sh->min_height = td->fnt->hgt + (oy + oy);
2929                 sh->max_width = 256 * td->fnt->wid + (ox + ox);
2930                 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
2931         }
2932
2933         /* Resize increment */
2934         sh->flags |= PResizeInc;
2935         sh->width_inc = td->fnt->wid;
2936         sh->height_inc = td->fnt->hgt;
2937
2938         /* Base window size */
2939         sh->flags |= PBaseSize;
2940         sh->base_width = (ox + ox);
2941         sh->base_height = (oy + oy);
2942
2943         /* Use the size hints */
2944         XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
2945
2946         /* Map the window */
2947         Infowin_map();
2948
2949 #ifdef USE_XIM
2950         /* Make WM Hints */
2951         wh = XAllocWMHints();
2952         if(wh == NULL) quit("XAllocWMHints failed");
2953         wh->flags = InputHint;
2954         wh->input = True;
2955         XSetWMHints(Metadpy->dpy, Infowin->win, wh);
2956 #endif
2957
2958         /* Move the window to requested location */
2959         if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
2960
2961
2962         /* Initialize the term */
2963         term_init(t, cols, rows, num);
2964
2965         /* Use a "soft" cursor */
2966         t->soft_cursor = TRUE;
2967
2968         /* Erase with "white space" */
2969         t->attr_blank = TERM_WHITE;
2970         t->char_blank = ' ';
2971
2972         /* Hooks */
2973         t->xtra_hook = Term_xtra_x11;
2974         t->curs_hook = Term_curs_x11;
2975         t->bigcurs_hook = Term_bigcurs_x11;
2976         t->wipe_hook = Term_wipe_x11;
2977         t->text_hook = Term_text_x11;
2978
2979         /* Save the data */
2980         t->data = td;
2981
2982         /* Activate (important) */
2983         Term_activate(t);
2984
2985         /* Success */
2986         return (0);
2987 }
2988
2989
2990 /*
2991  * Initialization function for an "X11" module to Angband
2992  */
2993 errr init_x11(int argc, char *argv[])
2994 {
2995         int i;
2996
2997         concptr dpy_name = "";
2998
2999         int num_term = 3;
3000
3001         char filename[1024];
3002
3003         int pict_wid = 0;
3004         int pict_hgt = 0;
3005
3006         char *TmpData;
3007
3008         /* Parse args */
3009         for (i = 1; i < argc; i++)
3010         {
3011                 if (prefix(argv[i], "-d"))
3012                 {
3013                         dpy_name = &argv[i][2];
3014                         continue;
3015                 }
3016                 
3017                 if (prefix(argv[i], "-s"))
3018                 {
3019                         smoothRescaling = FALSE;
3020                         continue;
3021                 }
3022
3023                 if (prefix(argv[i], "-a"))
3024                 {
3025                         arg_graphics = GRAPHICS_ADAM_BOLT;
3026                         continue;
3027                 }
3028
3029                 if (prefix(argv[i], "-o"))
3030                 {
3031                         arg_graphics = GRAPHICS_ORIGINAL;
3032                         continue;
3033                 }
3034
3035                 if (prefix(argv[i], "-b"))
3036                 {
3037                         arg_bigtile = use_bigtile = TRUE;
3038                         continue;
3039                 }
3040
3041                 if (prefix(argv[i], "-n"))
3042                 {
3043                         num_term = atoi(&argv[i][2]);
3044                         if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
3045                         else if (num_term < 1) num_term = 1;
3046                         continue;
3047                 }
3048
3049                 if (prefix(argv[i], "--"))
3050                 {
3051                         /* Ignore */
3052                         continue;
3053                 }
3054
3055                 plog_fmt("Ignoring option: %s", argv[i]);
3056         }
3057
3058 #ifdef USE_LOCALE
3059
3060 #ifdef JP
3061         /* Get locale information from environment variables */
3062         setlocale(LC_ALL, "");
3063
3064 #ifdef DEFAULT_LOCALE
3065         if(!strcmp(setlocale(LC_ALL, NULL), "C")){
3066                 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
3067                 setlocale(LC_ALL, DEFAULT_LOCALE);
3068         }
3069 #endif
3070
3071         if(!strcmp(setlocale(LC_ALL, NULL), "C"))
3072         {
3073                 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
3074         }
3075
3076         if(!XSupportsLocale()){
3077                 printf("can't support locale in X\n");
3078                 setlocale(LC_ALL, "C");
3079         }
3080 #else
3081         /* Set locale to "C" without using environment variables */
3082         setlocale(LC_ALL, "C");
3083 #endif /* JP */
3084
3085 #endif /* USE_LOCALE */
3086
3087
3088         /* Init the Metadpy if possible */
3089         if (Metadpy_init_name(dpy_name)) return (-1);
3090
3091
3092         /* Prepare cursor color */
3093         MAKE(xor, infoclr);
3094         Infoclr_set(xor);
3095         Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
3096
3097
3098         /* Prepare normal colors */
3099         for (i = 0; i < 256; ++i)
3100         {
3101                 Pixell pixel;
3102
3103                 MAKE(clr[i], infoclr);
3104
3105                 Infoclr_set(clr[i]);
3106
3107                 /* Acquire Angband colors */
3108                 color_table[i][0] = angband_color_table[i][0];
3109                 color_table[i][1] = angband_color_table[i][1];
3110                 color_table[i][2] = angband_color_table[i][2];
3111                 color_table[i][3] = angband_color_table[i][3];
3112
3113                 /* Default to monochrome */
3114                 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
3115
3116                 /* Handle color */
3117                 if (Metadpy->color)
3118                 {
3119                         /* Create pixel */
3120                         pixel = create_pixel(Metadpy->dpy,
3121                                              color_table[i][1],
3122                                              color_table[i][2],
3123                                              color_table[i][3]);
3124                 }
3125
3126                 /* Initialize the color */
3127                 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
3128         }
3129
3130
3131         /* Prepare required atoms. */
3132         set_atoms();
3133
3134
3135         /* Initialize the windows */
3136         for (i = 0; i < num_term; i++)
3137         {
3138                 term_data *td = &data[i];
3139
3140                 /* Initialize the term_data */
3141                 term_data_init(td, i);
3142
3143                 /* Save global entry */
3144                 angband_term[i] = Term;
3145         }
3146
3147         /* Raise the "Angband" window */
3148         Infowin_set(data[0].win);
3149         Infowin_raise();
3150
3151         /* Activate the "Angband" window screen */
3152         Term_activate(&data[0].t);
3153
3154 #ifdef USE_XIM
3155         {
3156                 char *p;
3157                 p = XSetLocaleModifiers("");
3158                 if(!p || !*p){
3159                         p = XSetLocaleModifiers("@im=");
3160                 }
3161 /*              printf("XMODIFIERS=\"%s\"\n", p); */
3162         }
3163         XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3164 #endif
3165
3166         /* initialize sound */
3167         if (arg_sound) init_sound();
3168
3169         /* Try graphics */
3170         switch (arg_graphics)
3171         {
3172         case GRAPHICS_ORIGINAL:
3173                 /* Try the "8x8.bmp" file */
3174                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
3175
3176                 /* Use the "8x8.bmp" file if it exists */
3177                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3178                 {
3179                         /* Use graphics */
3180                         use_graphics = TRUE;
3181
3182                         pict_wid = pict_hgt = 8;
3183
3184                         ANGBAND_GRAF = "old";
3185                         break;
3186                 }
3187                 /* Fall through */
3188
3189         case GRAPHICS_ADAM_BOLT:
3190                 /* Try the "16x16.bmp" file */
3191                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
3192
3193                 /* Use the "16x16.bmp" file if it exists */
3194                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3195                 {
3196                         /* Use graphics */
3197                         use_graphics = TRUE;
3198
3199                         pict_wid = pict_hgt = 16;
3200
3201                         ANGBAND_GRAF = "new";
3202
3203                         break;
3204                 }
3205         }
3206
3207         /* Load graphics */
3208         if (use_graphics)
3209         {
3210                 Display *dpy = Metadpy->dpy;
3211
3212                 XImage *tiles_raw;
3213
3214                 /* Load the graphical tiles */
3215                 tiles_raw = ReadBMP(dpy, filename);
3216
3217                 /* Initialize the windows */
3218                 for (i = 0; i < num_term; i++)
3219                 {
3220                         term_data *td = &data[i];
3221
3222                         term *t = &td->t;
3223
3224                         /* Graphics hook */
3225                         t->pict_hook = Term_pict_x11;
3226
3227                         /* Use graphics sometimes */
3228                         t->higher_pict = TRUE;
3229
3230                         /* Resize tiles */
3231                         td->tiles =
3232                         ResizeImage(dpy, tiles_raw,
3233                                     pict_wid, pict_hgt,
3234                                     td->fnt->twid, td->fnt->hgt);
3235                 }
3236
3237                 /* Initialize the transparency masks */
3238                 for (i = 0; i < num_term; i++)
3239                 {
3240                         term_data *td = &data[i];
3241                         int ii, jj;
3242                         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
3243                         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
3244                         int total;
3245
3246
3247                         /* Determine total bytes needed for image */
3248                         ii = 1;
3249                         jj = (depth - 1) >> 2;
3250                         while (jj >>= 1) ii <<= 1;
3251                         total = td->fnt->twid * td->fnt->hgt * ii;
3252                         
3253                         
3254                         TmpData = (char *)malloc(total);
3255
3256                         td->TmpImage = XCreateImage(dpy,visual,depth,
3257                                 ZPixmap, 0, TmpData,
3258                                 td->fnt->twid, td->fnt->hgt, 8, 0);
3259
3260                 }
3261
3262                 /* Free tiles_raw? XXX XXX */
3263         }
3264
3265         /* Success */
3266         return (0);
3267 }
3268
3269 #endif /* USE_X11 */