OSDN Git Service

8169190c61b0b4bacb7ceb0fbc40810037575172
[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) dad = Metadpy->root;
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         return (0);
956 }
957
958
959 /*
960  * Init an infofnt by its Name
961  *
962  * Inputs:
963  *      name: The name of the requested Font
964  */
965 static void Infofnt_init_data(concptr name)
966
967 {
968         XFontSet info;
969         char **missing_list;
970         int missing_count;
971         char *default_font;
972
973         /*** Load the info Fresh, using the name ***/
974
975         /* If the name is not given, report an error */
976         if (!name || !*name) quit("Missing font!");
977
978         /* Attempt to load the font */
979         info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
980         if(missing_count > 0){
981                 printf("missing font(s): \n");
982                 while(missing_count-- > 0){
983                         printf("\t%s\n", missing_list[missing_count]);
984                 }
985                 XFreeStringList(missing_list);
986         }
987
988         /* The load failed, try to recover */
989         if (!info) quit_fmt("Failed to find font:\"%s\"", name);
990
991         /*** Init the font ***/
992
993         /* Wipe the thing */
994         (void)WIPE(Infofnt, infofnt);
995
996         /* Attempt to prepare it */
997         if (Infofnt_prepare(info))
998         {
999                 /* Free the font */
1000                 XFreeFontSet(Metadpy->dpy, info);
1001
1002                 /* Fail */
1003                 quit_fmt("Failed to prepare font:\"%s\"", name);
1004         }
1005
1006         /* Save a copy of the font name */
1007         Infofnt->name = string_make(name);
1008
1009         /* Mark it as nukable */
1010         Infofnt->nuke = 1;
1011 }
1012
1013
1014 /*
1015  * Standard Text
1016  */
1017 static errr Infofnt_text_std(int x, int y, concptr str, int len)
1018 {
1019         int i;
1020
1021
1022         /*** Do a brief info analysis ***/
1023
1024         /* Do nothing if the string is null */
1025         if (!str || !*str) return (-1);
1026
1027         /* Get the length of the string */
1028         if (len < 0) len = strlen(str);
1029
1030         /*** Decide where to place the string, vertically ***/
1031
1032         /* Ignore Vertical Justifications */
1033         y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
1034
1035
1036         /*** Decide where to place the string, horizontally ***/
1037
1038         /* Line up with x at left edge of column 'x' */
1039         x = (x * Infofnt->wid) + Infowin->ox;
1040
1041
1042         /*** Actually draw 'str' onto the infowin ***/
1043
1044         /*** Handle the fake mono we can enforce on fonts ***/
1045
1046         /* Monotize the font */
1047         if (Infofnt->mono)
1048         {
1049                 /* Do each character */
1050                 for (i = 0; i < len; ++i)
1051                 {
1052                         /* Note that the Infoclr is set up to contain the Infofnt */
1053                         XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1054                                          x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
1055                 }
1056         }
1057
1058         /* Assume monoospaced font */
1059         else
1060         {
1061                 /* Note that the Infoclr is set up to contain the Infofnt */
1062                 iconv_t cd = iconv_open("UTF-8", "EUC-JP");
1063                 size_t inlen = len;
1064                 size_t outlen = len * 2;
1065                 char *kanji = malloc(outlen);
1066                 char *sp; char *kp = kanji;
1067                 char sbuf[1024];
1068                 my_strcpy(sbuf, str, sizeof(sbuf));
1069                 sp = sbuf;
1070                 iconv(cd, &sp, &inlen, &kp, &outlen);
1071                 iconv_close(cd);
1072
1073                 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
1074                                 Infoclr->gc, x, y, kanji, kp-kanji);
1075                 free(kanji);
1076         }
1077
1078         /* Success */
1079         return (0);
1080 }
1081
1082
1083 /*
1084  * Painting where text would be
1085  */
1086 static errr Infofnt_text_non(int x, int y, concptr str, int len)
1087 {
1088         int w, h;
1089
1090
1091         /*** Find the width ***/
1092
1093         /* Negative length is a flag to count the characters in str */
1094         if (len < 0) len = strlen(str);
1095
1096         /* The total width will be 'len' chars * standard width */
1097         w = len * Infofnt->wid;
1098
1099
1100         /*** Find the X dimensions ***/
1101
1102         /* Line up with x at left edge of column 'x' */
1103         x = x * Infofnt->wid + Infowin->ox;
1104
1105
1106         /*** Find other dimensions ***/
1107
1108         /* Simply do 'Infofnt->hgt' (a single row) high */
1109         h = Infofnt->hgt;
1110
1111         /* Simply do "at top" in row 'y' */
1112         y = y * h + Infowin->oy;
1113
1114
1115         /*** Actually 'paint' the area ***/
1116
1117         /* Just do a Fill Rectangle */
1118         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
1119
1120         /* Success */
1121         return (0);
1122 }
1123
1124
1125
1126 /*************************************************************************/
1127
1128
1129 /*
1130  * Angband specific code follows... (ANGBAND)
1131  */
1132
1133
1134 /*
1135  * Hack -- cursor color
1136  */
1137 static infoclr *xor;
1138
1139 /*
1140  * Actual color table
1141  */
1142 static infoclr *clr[256];
1143
1144 /*
1145  * Color info (unused, red, green, blue).
1146  */
1147 static byte color_table[256][4];
1148
1149 /*
1150  * Forward declare
1151  */
1152 typedef struct term_data term_data;
1153
1154 /*
1155  * A structure for each "term"
1156  */
1157 struct term_data
1158 {
1159         term t;
1160
1161         infofnt *fnt;
1162         infowin *win;
1163
1164         XImage *tiles;
1165
1166         /* Tempory storage for overlaying tiles. */
1167         XImage *TmpImage;
1168 };
1169
1170
1171 /*
1172  * The number of term data structures
1173  */
1174 #define MAX_TERM_DATA 8
1175
1176 /*
1177  * The array of term data structures
1178  */
1179 static term_data data[MAX_TERM_DATA];
1180
1181
1182 /* Use short names for the most commonly used elements of various structures. */
1183 #define DPY (Metadpy->dpy)
1184 #define WIN (Infowin->win)
1185
1186
1187 /* Describe a set of co-ordinates. */
1188 typedef struct co_ord co_ord;
1189 struct co_ord
1190 {
1191         int x;
1192         int y;
1193 };
1194
1195
1196 /*
1197  * A special structure to store information about the text currently
1198  * selected.
1199  */
1200 typedef struct x11_selection_type x11_selection_type;
1201 struct x11_selection_type
1202 {
1203         bool select; /* The selection is currently in use. */
1204         bool drawn; /* The selection is currently displayed. */
1205         term *t; /* The window where the selection is found. */
1206         co_ord init; /* The starting co-ordinates. */
1207         co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1208         co_ord old; /* The previous end co-ordinates. */
1209         Time time; /* The time at which the selection was finalised. */
1210 };
1211
1212 static x11_selection_type s_ptr[1];
1213
1214
1215 /*
1216  * Process a keypress event
1217  *
1218  * Also appears in "main-xaw.c".
1219  */
1220 static void react_keypress(XKeyEvent *xev)
1221 {
1222         int i, n, mc, ms, mo, mx;
1223
1224         uint ks1;
1225
1226         XKeyEvent *ev = (XKeyEvent*)(xev);
1227
1228         KeySym ks;
1229
1230         char buf[128];
1231         char msg[128];
1232
1233 #ifdef USE_XIM
1234         int valid_keysym = TRUE;
1235 #endif
1236
1237         /* Check for "normal" keypresses */
1238 #ifdef USE_XIM
1239         if(Focuswin && Focuswin->xic){
1240                 Status status;
1241                 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1242                 if(status == XBufferOverflow){
1243                         printf("Input is too long, and dropped\n");
1244                         return;
1245                 }
1246                 if(status != XLookupKeySym && status != XLookupBoth){
1247                         valid_keysym = FALSE;
1248                 }
1249         }else{
1250                 n = XLookupString(ev, buf, 125, &ks, NULL);
1251         }
1252 #else
1253         n = XLookupString(ev, buf, 125, &ks, NULL);
1254 #endif
1255
1256         /* Terminate */
1257         buf[n] = '\0';
1258
1259 #ifdef USE_XIM
1260         if(!valid_keysym){
1261                 /* Enqueue the normal key(s) */
1262                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1263
1264                 /* All done */
1265                 return;
1266         }
1267 #endif
1268
1269         /* Hack -- Ignore "modifier keys" */
1270         if (IsModifierKey(ks)) return;
1271
1272
1273         /* Hack -- convert into an unsigned int */
1274         ks1 = (uint)(ks);
1275
1276         /* Extract four "modifier flags" */
1277         mc = (ev->state & ControlMask) ? TRUE : FALSE;
1278         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1279         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1280         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1281
1282
1283         /* Normal keys with no modifiers */
1284         if (n && !mo && !mx && !IsSpecialKey(ks))
1285         {
1286                 /* Enqueue the normal key(s) */
1287                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1288
1289                 /* All done */
1290                 return;
1291         }
1292
1293
1294         /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1295         switch (ks1)
1296         {
1297                 case XK_Escape:
1298                 {
1299                         Term_keypress(ESCAPE);
1300                         return;
1301                 }
1302
1303                 case XK_Return:
1304                 {
1305                         Term_keypress('\r');
1306                         return;
1307                 }
1308
1309                 case XK_Tab:
1310                 {
1311                         Term_keypress('\t');
1312                         return;
1313                 }
1314
1315                 case XK_Delete:
1316                 {
1317                         Term_keypress(0x7f);
1318                         return;
1319                 }
1320                 case XK_BackSpace:
1321                 {
1322                         Term_keypress('\010');
1323                         return;
1324                 }
1325         }
1326
1327
1328         /* Hack -- Use the KeySym */
1329         if (ks)
1330         {
1331                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1332                         mc ? "N" : "", ms ? "S" : "",
1333                         mo ? "O" : "", mx ? "M" : "",
1334                         (unsigned long)(ks), 13);
1335         }
1336
1337         /* Hack -- Use the Keycode */
1338         else
1339         {
1340                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1341                         mc ? "N" : "", ms ? "S" : "",
1342                         mo ? "O" : "", mx ? "M" : "",
1343                         ev->keycode, 13);
1344         }
1345
1346         /* Enqueue the "macro trigger" string */
1347         for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1348
1349
1350         /* Hack -- auto-define macros as needed */
1351         if (n && (macro_find_exact(msg) < 0))
1352         {
1353                 /* Create a macro */
1354                 macro_add(msg, buf);
1355         }
1356 }
1357
1358
1359 /*
1360  * Find the square a particular pixel is part of.
1361  */
1362 static void pixel_to_square(int * const x, int * const y,
1363         const int ox, const int oy)
1364 {
1365         (*x) = (ox - Infowin->ox) / Infofnt->wid;
1366         (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1367 }
1368
1369 /*
1370  * Find the pixel at the top-left corner of a square.
1371  */
1372 static void square_to_pixel(int * const x, int * const y,
1373         const int ox, const int oy)
1374 {
1375         (*x) = ox * Infofnt->wid + Infowin->ox;
1376         (*y) = oy * Infofnt->hgt + Infowin->oy;
1377 }
1378
1379 /*
1380  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
1381  */
1382 static void sort_co_ord(co_ord *min, co_ord *max,
1383         const co_ord *b, const co_ord *a)
1384 {
1385         min->x = MIN(a->x, b->x);
1386         min->y = MIN(a->y, b->y);
1387         max->x = MAX(a->x, b->x);
1388         max->y = MAX(a->y, b->y);
1389 }
1390
1391 /*
1392  * Remove the selection by redrawing it.
1393  */
1394 static void mark_selection_clear(int x1, int y1, int x2, int y2)
1395 {
1396         Term_redraw_section(x1,y1,x2,y2);
1397 }
1398
1399 /*
1400  * Select an area by drawing a grey box around it.
1401  * NB. These two functions can cause flicker as the selection is modified,
1402  * as the game redraws the entire marked section.
1403  */
1404 static void mark_selection_mark(int x1, int y1, int x2, int y2)
1405 {
1406         square_to_pixel(&x1, &y1, x1, y1);
1407         square_to_pixel(&x2, &y2, x2, y2);
1408         XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
1409                 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
1410 }
1411
1412 /*
1413  * Mark a selection by drawing boxes around it (for now).
1414  */
1415 static void mark_selection(void)
1416 {
1417         co_ord min, max;
1418         term *old = Term;
1419         bool draw = s_ptr->select;
1420         bool clear = s_ptr->drawn;
1421
1422         /* Open the correct term if necessary. */
1423         if (s_ptr->t != old) Term_activate(s_ptr->t);
1424
1425         if (clear)
1426         {
1427                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
1428                 mark_selection_clear(min.x, min.y, max.x, max.y);
1429         }
1430         if (draw)
1431         {
1432                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1433                 mark_selection_mark(min.x, min.y, max.x, max.y);
1434         }
1435
1436         /* Finish on the current term. */
1437         if (s_ptr->t != old) Term_activate(old);
1438
1439         s_ptr->old.x = s_ptr->cur.x;
1440         s_ptr->old.y = s_ptr->cur.y;
1441         s_ptr->drawn = s_ptr->select;
1442 }
1443
1444 /*
1445  * Forget a selection for one reason or another.
1446  */
1447 static void copy_x11_release(void)
1448 {
1449         /* Deselect the current selection. */
1450         s_ptr->select = FALSE;
1451
1452         /* Remove its graphical represesntation. */
1453         mark_selection();
1454 }
1455
1456 /*
1457  * Start to select some text on the screen.
1458  */
1459 static void copy_x11_start(int x, int y)
1460 {
1461         if (s_ptr->select) copy_x11_release();
1462
1463         /* Remember where the selection started. */
1464         s_ptr->t = Term;
1465         s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
1466         s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
1467 }
1468
1469 /*
1470  * Respond to movement of the mouse when selecting text.
1471  */
1472 static void copy_x11_cont(int x, int y, unsigned int buttons)
1473 {
1474         /* Use the nearest square within bounds if the mouse is outside. */
1475         x = MIN(MAX(x, 0), Term->wid-1);
1476         y = MIN(MAX(y, 0), Term->hgt-1);
1477
1478         /* The left mouse button isn't pressed. */
1479         if (~buttons & Button1Mask) return;
1480
1481         /* Not a selection in this window. */
1482         if (s_ptr->t != Term) return;
1483
1484         /* Not enough movement. */
1485         if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
1486
1487         /* Something is being selected. */
1488         s_ptr->select = TRUE;
1489
1490         /* Track the selection. */
1491         s_ptr->cur.x = x;
1492         s_ptr->cur.y = y;
1493
1494         /* Hack - display it inefficiently. */
1495         mark_selection();
1496 }
1497
1498 /*
1499  * Respond to release of the left mouse button by putting the selected text in
1500  * the primary buffer.
1501  */
1502 static void copy_x11_end(const Time time)
1503 {
1504         /* No selection. */
1505         if (!s_ptr->select) return;
1506
1507         /* Not a selection in this window. */
1508         if (s_ptr->t != Term) return;
1509
1510         /* Remember when the selection was finalised. */
1511         s_ptr->time = time;
1512
1513         /* Acquire the primary selection. */
1514         XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
1515         if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
1516         {
1517                 /* Failed to acquire the selection, so forget it. */
1518                 /* bell("Failed to acquire primary buffer."); */
1519                 s_ptr->select = FALSE;
1520                 mark_selection();
1521         }
1522 }
1523
1524
1525 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
1526
1527 /*
1528  * Set the required variable atoms at start-up to avoid errors later.
1529  */
1530 static void set_atoms(void)
1531 {
1532         xa_targets = XInternAtom(DPY, "TARGETS", False);
1533         xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
1534         xa_text = XInternAtom(DPY, "TEXT", False);
1535         xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
1536 }
1537
1538
1539 static Atom request_target = 0;
1540
1541 /*
1542  * Send a message to request that the PRIMARY buffer be sent here.
1543  */
1544 static void paste_x11_request(Atom target, const Time time)
1545 {
1546         /*
1547          * It's from some sample programs on the web.
1548          * What does it mean? -- XXX
1549          */
1550         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1551
1552         /* Check the owner. */
1553         if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
1554         {
1555                 /* No selection. */
1556                 /* bell("No selection found."); */
1557                 return;
1558         }
1559
1560         request_target = target;
1561     
1562         /* Request the event */
1563         XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
1564 }
1565
1566
1567 /*
1568  * Add the contents of the PRIMARY buffer to the input queue.
1569  *
1570  * Hack - This doesn't use the "time" of the event, and so accepts anything a
1571  * client tries to send it.
1572  */
1573 static void paste_x11_accept(const XSelectionEvent *ptr)
1574 {
1575         unsigned long left;
1576         const long offset = 0;
1577         const long length = 32000;
1578         XTextProperty xtextproperty;
1579         errr err = 0;
1580
1581         /*
1582          * It's from some sample programs on the web.
1583          * What does it mean? -- XXX
1584          */
1585         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
1586
1587
1588         /* Failure. */
1589         if (ptr->property == None)
1590         {
1591                 if (request_target == xa_compound_text)
1592                 {
1593                         /* Re-request as STRING */
1594                         paste_x11_request(XA_STRING, ptr->time);
1595                 }
1596                 else
1597                 {
1598                         request_target = 0;
1599                         plog("Paste failure (remote client could not send).");
1600                 }
1601                 return;
1602         }
1603
1604         if (ptr->selection != XA_PRIMARY)
1605         {
1606                 plog("Paste failure (remote client did not send primary selection).");
1607                 return;
1608         }
1609
1610         if (ptr->target != request_target)
1611         {
1612                 plog("Paste failure (selection in unknown format).");
1613                 return;
1614         }
1615
1616         /* Get text */
1617         if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
1618                                length, TRUE, request_target,
1619                                &xtextproperty.encoding,
1620                                &xtextproperty.format,
1621                                &xtextproperty.nitems,
1622                                &left,
1623                                &xtextproperty.value)
1624             != Success)
1625         {
1626                 /* Failure */
1627                 return;
1628         }
1629
1630         if (request_target == xa_compound_text)
1631         {
1632                 char **list;
1633                 int count;
1634                 
1635                 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
1636
1637                 if (list)
1638                 {
1639                         int i;
1640
1641                         for (i = 0; i < count; i++)
1642                         {
1643                                 /* Paste the text. */
1644                                 err = type_string(list[i], 0);
1645
1646                                 if (err) break;
1647                         }
1648
1649                         /* Free the string */
1650                         XFreeStringList(list);
1651                 }
1652         }
1653         else /* if (request_target == XA_STRING) */
1654         {
1655                 /* Paste the text. */
1656                 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
1657         }
1658
1659         /* Free the data pasted. */
1660         XFree(xtextproperty.value); 
1661
1662         /* No room. */
1663         if (err)
1664         {
1665                 plog("Paste failure (too much text selected).");
1666         }
1667 }
1668
1669
1670 /*
1671  * Add a character to a string in preparation for sending it to another
1672  * client as a STRING.
1673  * This doesn't change anything, as clients tend not to have difficulty in
1674  * receiving this format (although the standard specifies a restricted set).
1675  * Strings do not have a colour.
1676  */
1677 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
1678 {
1679         char buf[1024];
1680         char *list[1000];
1681         co_ord max, min;
1682         TERM_LEN x,y;
1683         int l,n;
1684         TERM_COLOR a;
1685         char c;
1686
1687         /* Too old, or incorrect call. */
1688         if (rq->time < s_ptr->time) return FALSE;
1689
1690         /* Work out which way around to paste. */
1691         sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
1692
1693         /* Paranoia. */
1694         if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
1695         {
1696                 /* bell("Someone stole my selection!"); */
1697                 return FALSE;
1698         }
1699
1700         /* Delete the old value of the property. */
1701         XDeleteProperty(DPY, rq->requestor, rq->property);
1702
1703         for (n = 0, y = 0; y < Term->hgt; y++)
1704         {
1705 #ifdef JP
1706                 int kanji = 0;
1707 #endif
1708                 if (y < min.y) continue;
1709                 if (y > max.y) break;
1710
1711                 for (l = 0, x = 0; x < Term->wid; x++)
1712                 {
1713 #ifdef JP
1714                         if (x > max.x) break;
1715
1716                         /* Find the character. */
1717                         Term_what(x, y, &a, &c);
1718
1719                         if (1 == kanji) kanji = 2;
1720                         else if (iskanji(c)) kanji = 1;
1721                         else kanji = 0;
1722
1723                         if (x < min.x) continue;
1724
1725                         /*
1726                          * A single kanji character was divided in two...
1727                          * Delete the garbage.
1728                          */
1729                         if ((2 == kanji && x == min.x) ||
1730                             (1 == kanji && x == max.x))
1731                                 c = ' ';
1732 #else
1733                         if (x > max.x) break;
1734                         if (x < min.x) continue;
1735
1736                         /* Find the character. */
1737                         Term_what(x, y, &a, &c);
1738 #endif
1739
1740                         /* Add it. */
1741                         buf[l] = c;
1742                         l++;
1743                 }
1744
1745                 /* Ignore trailing spaces */
1746                 while (buf[l-1] == ' ') l--;
1747
1748                 /* Terminate all line unless it's single line. */
1749                 if (min.y != max.y)
1750                 {
1751                         buf[l] = '\n';
1752                         l++;
1753                 }
1754
1755                 /* End of string */
1756                 buf[l] = '\0';
1757
1758                 list[n++] = (char *)string_make(buf);
1759         }
1760
1761         /* End of the list */
1762         list[n] = NULL;
1763
1764
1765         if (rq->target == XA_STRING)
1766         {
1767                 for (n = 0; list[n]; n++)
1768                 {
1769                         /* Send the (non-empty) string. */
1770                         XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
1771                                         PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
1772                 }
1773         }
1774
1775         else if (rq->target == xa_text || 
1776                  rq->target == xa_compound_text)
1777         {
1778                 XTextProperty text_prop;
1779                 XICCEncodingStyle style;
1780
1781                 if (rq->target == xa_text)
1782                         style = XStdICCTextStyle;
1783                 else /* if (rq->target == xa_compound_text) */
1784                         style = XCompoundTextStyle;
1785
1786                 if (Success ==
1787                     XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
1788                 {
1789                         /* Send the compound text */
1790                         XChangeProperty(DPY,
1791                                         rq->requestor,
1792                                         rq->property,
1793                                         text_prop.encoding,
1794                                         text_prop.format,
1795                                         PropModeAppend,
1796                                         text_prop.value,
1797                                         text_prop.nitems);
1798                                 
1799                         /* Free the data. */
1800                         XFree(text_prop.value);
1801                 }
1802         }
1803
1804         /* Free the list of strings */
1805         for (n = 0; list[n]; n++)
1806         {
1807                 string_free(list[n]);
1808         }
1809
1810         return TRUE;
1811 }
1812
1813 /*
1814  * Send some text requested by another X client.
1815  */
1816 static void paste_x11_send(XSelectionRequestEvent *rq)
1817 {
1818         XEvent event;
1819         XSelectionEvent *ptr = &(event.xselection);
1820
1821         /* Set the event parameters. */
1822         ptr->type = SelectionNotify;
1823         ptr->property = rq->property;
1824         ptr->display = rq->display;
1825         ptr->requestor = rq->requestor;
1826         ptr->selection = rq->selection;
1827         ptr->target = rq->target;
1828         ptr->time = rq->time;
1829
1830         /* Paste the appropriate information for each target type.
1831          * Note that this currently rejects MULTIPLE targets.
1832          */
1833
1834         if (rq->target == XA_STRING ||
1835             rq->target == xa_text ||
1836             rq->target == xa_compound_text)
1837         {
1838                 if (!paste_x11_send_text(rq))
1839                         ptr->property = None;
1840         }
1841         else if (rq->target == xa_targets)
1842         {
1843                 Atom target_list[4];
1844                 target_list[0] = XA_STRING;
1845                 target_list[1] = xa_text;
1846                 target_list[2] = xa_compound_text;
1847                 target_list[3] = xa_targets;
1848                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1849                         (8 * sizeof(target_list[0])), PropModeReplace,
1850                         (unsigned char *)target_list,
1851                         (sizeof(target_list) / sizeof(target_list[0])));
1852         }
1853         else if (rq->target == xa_timestamp)
1854         {
1855                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
1856                         (8 * sizeof(Time)), PropModeReplace,
1857                         (unsigned char *)s_ptr->time, 1);
1858         }
1859         else
1860         {
1861                 ptr->property = None;
1862         }
1863
1864         /* Send whatever event we're left with. */
1865         XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
1866 }
1867
1868
1869 /*
1870  * Handle various events conditional on presses of a mouse button.
1871  */
1872 static void handle_button(Time time, int x, int y, int button,
1873         bool press)
1874 {
1875         /* The co-ordinates are only used in Angband format. */
1876         pixel_to_square(&x, &y, x, y);
1877
1878         if (press && button == 1) copy_x11_start(x, y);
1879         if (!press && button == 1) copy_x11_end(time);
1880         if (!press && button == 2) paste_x11_request(xa_compound_text, time);
1881 }
1882
1883
1884 /*
1885  * Process events
1886  */
1887 static errr CheckEvent(bool wait)
1888 {
1889         term_data *old_td = (term_data*)(Term->data);
1890
1891         XEvent xev_body, *xev = &xev_body;
1892
1893         term_data *td = NULL;
1894         infowin *iwin = NULL;
1895
1896         int i;
1897
1898 #ifdef USE_XIM
1899         do
1900         {
1901 #endif
1902
1903                 /* Do not wait unless requested */
1904                 if (!wait && !XPending(Metadpy->dpy)) return (1);
1905
1906                 /*
1907                  * Hack - redraw the selection, if needed.
1908                  * This doesn't actually check that one of its squares was drawn to,
1909                  * only that this may have happened.
1910                  */
1911                 if (s_ptr->select && !s_ptr->drawn) mark_selection();
1912
1913                 /* Load the Event */
1914                 XNextEvent(Metadpy->dpy, xev);
1915
1916 #ifdef USE_XIM
1917         } while (XFilterEvent(xev, xev->xany.window));
1918 #endif
1919
1920         /* Notice new keymaps */
1921         if (xev->type == MappingNotify)
1922         {
1923                 XRefreshKeyboardMapping(&xev->xmapping);
1924                 return 0;
1925         }
1926
1927
1928         /* Scan the windows */
1929         for (i = 0; i < MAX_TERM_DATA; i++)
1930         {
1931                 if (!data[i].win) continue;
1932                 if (xev->xany.window == data[i].win->win)
1933                 {
1934                         td = &data[i];
1935                         iwin = td->win;
1936                         break;
1937                 }
1938         }
1939
1940         /* Unknown window */
1941         if (!td || !iwin) return (0);
1942
1943
1944         /* Hack -- activate the Term */
1945         Term_activate(&td->t);
1946
1947         /* Hack -- activate the window */
1948         Infowin_set(iwin);
1949
1950
1951         /* Switch on the Type */
1952         switch (xev->type)
1953         {
1954                 case ButtonPress:
1955                 case ButtonRelease:
1956                 {
1957                         bool press = (xev->type == ButtonPress);
1958
1959                         /* Where is the mouse */
1960                         int x = xev->xbutton.x;
1961                         int y = xev->xbutton.y;
1962
1963                         int z;
1964
1965                         /* Which button is involved */
1966                         if (xev->xbutton.button == Button1) z = 1;
1967                         else if (xev->xbutton.button == Button2) z = 2;
1968                         else if (xev->xbutton.button == Button3) z = 3;
1969                         else if (xev->xbutton.button == Button4) z = 4;
1970                         else if (xev->xbutton.button == Button5) z = 5;
1971                         else z = 0;
1972
1973                         /* XXX Handle */
1974                         handle_button(xev->xbutton.time, x, y, z, press);
1975
1976                         break;
1977                 }
1978
1979                 case EnterNotify:
1980                 case LeaveNotify:
1981                 {
1982                         /* XXX Handle */
1983
1984                         break;
1985                 }
1986
1987                 case MotionNotify:
1988                 {
1989                         /* Where is the mouse */
1990                         int x = xev->xmotion.x;
1991                         int y = xev->xmotion.y;
1992                         unsigned int z = xev->xmotion.state;
1993
1994                         /* Convert to co-ordinates Angband understands. */
1995                         pixel_to_square(&x, &y, x, y);
1996
1997                         /* Highlight the current square, if appropriate. */
1998                         /* highlight_square(window, y, x); */
1999
2000                         /* Alter the selection if appropriate. */
2001                         copy_x11_cont(x, y, z);
2002
2003                         /* XXX Handle */
2004
2005                         break;
2006                 }
2007
2008                 case SelectionNotify:
2009                 {
2010                         paste_x11_accept(&(xev->xselection));
2011                         break;
2012                 }
2013
2014                 case SelectionRequest:
2015                 {
2016                         paste_x11_send(&(xev->xselectionrequest));
2017                         break;
2018                 }
2019
2020                 case SelectionClear:
2021                 {
2022                         s_ptr->select = FALSE;
2023                         mark_selection();
2024                         break;
2025                 }
2026
2027                 case KeyRelease:
2028                 {
2029                         /* Nothing */
2030                         break;
2031                 }
2032
2033                 case KeyPress:
2034                 {
2035                         /* Hack -- use "old" term */
2036                         Term_activate(&old_td->t);
2037
2038                         /* Process the key */
2039                         react_keypress(&(xev->xkey));
2040
2041                         break;
2042                 }
2043
2044                 case Expose:
2045                 {
2046                         int x1, x2, y1, y2;
2047                         
2048                         /* Ignore "extra" exposes */
2049                         /*if (xev->xexpose.count) break;*/
2050
2051                         /* Clear the window */
2052                         /*Infowin_wipe();*/
2053                         
2054                         x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
2055                         x2 = (xev->xexpose.x + xev->xexpose.width -
2056                                  Infowin->ox)/Infofnt->wid;
2057                         
2058                         y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
2059                         y2 = (xev->xexpose.y + xev->xexpose.height -
2060                                  Infowin->oy)/Infofnt->hgt;
2061                         
2062                         Term_redraw_section(x1, y1, x2, y2);
2063
2064                         /* Redraw */
2065                         /*Term_redraw();*/
2066
2067                         break;
2068                 }
2069
2070                 case MapNotify:
2071                 {
2072                         Infowin->mapped = 1;
2073                         Term->mapped_flag = TRUE;
2074                         break;
2075                 }
2076
2077                 case UnmapNotify:
2078                 {
2079                         Infowin->mapped = 0;
2080                         Term->mapped_flag = FALSE;
2081                         break;
2082                 }
2083
2084                 /* Move and/or Resize */
2085                 case ConfigureNotify:
2086                 {
2087                         int cols, rows, wid, hgt;
2088
2089                         int ox = Infowin->ox;
2090                         int oy = Infowin->oy;
2091
2092                         /* Save the new Window Parms */
2093                         Infowin->x = xev->xconfigure.x;
2094                         Infowin->y = xev->xconfigure.y;
2095                         Infowin->w = xev->xconfigure.width;
2096                         Infowin->h = xev->xconfigure.height;
2097
2098                         /* Determine "proper" number of rows/cols */
2099                         cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2100                         rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2101
2102                         /* Hack -- minimal size */
2103                         if (cols < 1) cols = 1;
2104                         if (rows < 1) rows = 1;
2105
2106                         if (td == &data[0])
2107                         {
2108                                 /* Hack the main window must be at least 80x24 */
2109                                 if (cols < 80) cols = 80;
2110                                 if (rows < 24) rows = 24;
2111                         }
2112
2113                         /* Desired size of window */
2114                         wid = cols * td->fnt->wid + (ox + ox);
2115                         hgt = rows * td->fnt->hgt + (oy + oy);
2116
2117                         /* Resize the Term (if needed) */
2118                         Term_resize(cols, rows);
2119
2120                         /* Resize the windows if any "change" is needed */
2121                         if ((Infowin->w != wid) || (Infowin->h != hgt))
2122                         {
2123                                 /* Resize window */
2124                                 Infowin_set(td->win);
2125                                 Infowin_resize(wid, hgt);
2126                         }
2127
2128                         break;
2129                 }
2130 #ifdef USE_XIM
2131                 case FocusIn:
2132                 {
2133                         if(iwin->xic){
2134                                 XSetICFocus(iwin->xic);
2135                         }
2136                         Focuswin = iwin;
2137                         break;
2138                 }
2139                 case FocusOut:
2140                 {
2141                         if(iwin->xic){
2142                                 XUnsetICFocus(iwin->xic);
2143                         }
2144                         /* Focuswin = NULL;*/
2145                         break;
2146                 }
2147 #endif
2148         }
2149
2150
2151         /* Hack -- Activate the old term */
2152         Term_activate(&old_td->t);
2153
2154         /* Hack -- Activate the proper window */
2155         Infowin_set(old_td->win);
2156
2157
2158         /* Success */
2159         return (0);
2160 }
2161
2162
2163  /*
2164   * Standard sound names
2165   */
2166 static const concptr angband_sound_name[SOUND_MAX] =
2167 {
2168         "dummy",
2169         "hit",
2170         "miss",
2171         "flee",
2172         "drop",
2173         "kill",
2174         "level",
2175         "death",
2176         "study",
2177         "teleport",
2178         "shoot",
2179         "quaff",
2180         "zap",
2181         "walk",
2182         "tpother",
2183         "hitwall",
2184         "eat",
2185         "store1",
2186         "store2",
2187         "store3",
2188         "store4",
2189         "dig",
2190         "opendoor",
2191         "shutdoor",
2192         "tplevel",
2193         "scroll",
2194         "buy",
2195         "sell",
2196         "warn",
2197         "rocket",
2198         "n_kill",
2199         "u_kill",
2200         "quest",
2201         "heal",
2202         "x_heal",
2203         "bite",
2204         "claw",
2205         "m_spell",
2206         "summon",
2207         "breath",
2208         "ball",
2209         "m_heal",
2210         "atkspell",
2211         "evil",
2212         "touch",
2213         "sting",
2214         "crush",
2215         "slime",
2216         "wail",
2217         "winner",
2218         "fire",
2219         "acid",
2220         "elec",
2221         "cold",
2222         "illegal",
2223         "fail",
2224         "wakeup",
2225         "invuln",
2226         "fall",
2227         "pain",
2228         "destitem",
2229         "moan",
2230         "show",
2231         "unused",
2232         "explode",
2233         "glass",
2234         "reflect",
2235 };
2236
2237 /*
2238  * An array of sound file names
2239  */
2240 static concptr sound_file[SOUND_MAX];
2241
2242 /*
2243  * Check for existance of a file
2244  */
2245 static bool check_file(concptr s)
2246 {
2247         FILE *fff;
2248
2249         fff = fopen(s, "r");
2250         if (!fff) return (FALSE);
2251         
2252         fclose(fff);
2253         return (TRUE);
2254 }
2255
2256 /*
2257  * Initialize sound
2258  */
2259 static void init_sound(void)
2260 {
2261         int i;
2262         char wav[128];
2263         char buf[1024];
2264         char dir_xtra_sound[1024];
2265                 
2266         /* Build the "sound" path */
2267         path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
2268                 
2269         /* Prepare the sounds */
2270         for (i = 1; i < SOUND_MAX; i++)
2271         {
2272                 /* Extract name of sound file */
2273                 sprintf(wav, "%s.wav", angband_sound_name[i]);
2274                 
2275                 /* Access the sound */
2276                 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
2277                 
2278                 /* Save the sound filename, if it exists */
2279                 if (check_file(buf)) sound_file[i] = string_make(buf);
2280         }
2281         use_sound = TRUE;
2282         return;
2283 }
2284
2285 /*
2286  * Hack -- make a sound
2287  */
2288 static errr Term_xtra_x11_sound(int v)
2289 {
2290         char buf[1024];
2291         
2292         /* Sound disabled */
2293         if (!use_sound) return (1);
2294         
2295         /* Illegal sound */
2296         if ((v < 0) || (v >= SOUND_MAX)) return (1);
2297         
2298         /* Unknown sound */
2299         if (!sound_file[v]) return (1);
2300         
2301         sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
2302         
2303         return (system(buf) < 0);
2304         
2305 }
2306
2307
2308 /*
2309  * Handle "activation" of a term
2310  */
2311 static errr Term_xtra_x11_level(int v)
2312 {
2313         term_data *td = (term_data*)(Term->data);
2314
2315         /* Handle "activate" */
2316         if (v)
2317         {
2318                 /* Activate the window */
2319                 Infowin_set(td->win);
2320
2321                 /* Activate the font */
2322                 Infofnt_set(td->fnt);
2323         }
2324
2325         /* Success */
2326         return (0);
2327 }
2328
2329
2330 /*
2331  * React to changes
2332  */
2333 static errr Term_xtra_x11_react(void)
2334 {
2335         int i;
2336         
2337         if (Metadpy->color)
2338         {
2339                 /* Check the colors */
2340                 for (i = 0; i < 256; i++)
2341                 {
2342                         if ((color_table[i][0] != angband_color_table[i][0]) ||
2343                             (color_table[i][1] != angband_color_table[i][1]) ||
2344                             (color_table[i][2] != angband_color_table[i][2]) ||
2345                             (color_table[i][3] != angband_color_table[i][3]))
2346                         {
2347                                 Pixell pixel;
2348
2349                                 /* Save new values */
2350                                 color_table[i][0] = angband_color_table[i][0];
2351                                 color_table[i][1] = angband_color_table[i][1];
2352                                 color_table[i][2] = angband_color_table[i][2];
2353                                 color_table[i][3] = angband_color_table[i][3];
2354
2355                                 /* Create pixel */
2356                                 pixel = create_pixel(Metadpy->dpy,
2357                                                      color_table[i][1],
2358                                                      color_table[i][2],
2359                                                      color_table[i][3]);
2360
2361                                 /* Change the foreground */
2362                                 Infoclr_set(clr[i]);
2363                                 Infoclr_change_fg(pixel);
2364                         }
2365                 }
2366         }
2367
2368         /* Success */
2369         return (0);
2370 }
2371
2372
2373 /*
2374  * Handle a "special request"
2375  */
2376 static errr Term_xtra_x11(int n, int v)
2377 {
2378         /* Handle a subset of the legal requests */
2379         switch (n)
2380         {
2381                 /* Make a noise */
2382                 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
2383
2384                 /* Make a special sound */
2385                 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
2386
2387                 /* Flush the output XXX XXX */
2388                 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
2389
2390                 /* Process random events XXX */
2391                 case TERM_XTRA_BORED: return (CheckEvent(0));
2392
2393                 /* Process Events XXX */
2394                 case TERM_XTRA_EVENT: return (CheckEvent(v));
2395
2396                 /* Flush the events XXX */
2397                 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
2398
2399                 /* Handle change in the "level" */
2400                 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
2401
2402                 /* Clear the screen */
2403                 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
2404
2405                 /* Delay for some milliseconds */
2406                 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
2407
2408                 /* React to changes */
2409                 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
2410         }
2411
2412         /* Unknown */
2413         return (1);
2414 }
2415
2416
2417 /*
2418  * Draw the cursor as an inverted rectangle.
2419  *
2420  * Consider a rectangular outline like "main-mac.c".  XXX XXX
2421  */
2422 static errr Term_curs_x11(int x, int y)
2423 {
2424         if (use_graphics)
2425         {
2426                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2427                                x * Infofnt->wid + Infowin->ox,
2428                                y * Infofnt->hgt + Infowin->oy,
2429                                Infofnt->wid - 1, Infofnt->hgt - 1);
2430                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2431                                x * Infofnt->wid + Infowin->ox + 1,
2432                                y * Infofnt->hgt + Infowin->oy + 1,
2433                                Infofnt->wid - 3, Infofnt->hgt - 3);
2434         }
2435         else
2436         {
2437                 /* Draw the cursor */
2438                 Infoclr_set(xor);
2439
2440                 /* Hilite the cursor character */
2441                 Infofnt_text_non(x, y, " ", 1);
2442         }
2443
2444         /* Success */
2445         return (0);
2446 }
2447
2448
2449 /*
2450  * Draw the double width cursor
2451  */
2452 static errr Term_bigcurs_x11(int x, int y)
2453 {
2454         if (use_graphics)
2455         {
2456                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2457                                x * Infofnt->wid + Infowin->ox,
2458                                y * Infofnt->hgt + Infowin->oy,
2459                                Infofnt->twid - 1, Infofnt->hgt - 1);
2460                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
2461                                x * Infofnt->wid + Infowin->ox + 1,
2462                                y * Infofnt->hgt + Infowin->oy + 1,
2463                                Infofnt->twid - 3, Infofnt->hgt - 3);
2464         }
2465         else
2466         {
2467                 /* Draw the cursor */
2468                 Infoclr_set(xor);
2469
2470                 /* Hilite the cursor character */
2471                 Infofnt_text_non(x, y, "  ", 2);
2472         }
2473         /* Success */
2474         return (0);
2475 }
2476
2477
2478 /*
2479  * Erase some characters.
2480  */
2481 static errr Term_wipe_x11(int x, int y, int n)
2482 {
2483         /* Erase (use black) */
2484         Infoclr_set(clr[TERM_DARK]);
2485
2486         /* Mega-Hack -- Erase some space */
2487         Infofnt_text_non(x, y, "", n);
2488
2489         /* Redraw the selection if any, as it may have been obscured. (later) */
2490         s_ptr->drawn = FALSE;
2491
2492         /* Success */
2493         return (0);
2494 }
2495
2496
2497 /*
2498  * Draw some textual characters.
2499  */
2500 static errr Term_text_x11(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
2501 {
2502         /* Draw the text */
2503         Infoclr_set(clr[a]);
2504
2505         /* Draw the text */
2506         Infofnt_text_std(x, y, s, n);
2507
2508         /* Redraw the selection if any, as it may have been obscured. (later) */
2509         s_ptr->drawn = FALSE;
2510
2511         /* Success */
2512         return (0);
2513 }
2514
2515
2516 /*
2517  * Draw some graphical characters.
2518  */
2519 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)
2520 {
2521         int i, x1, y1;
2522
2523         TERM_COLOR a;
2524         char c;
2525
2526         TERM_COLOR ta;
2527         char tc;
2528
2529         int x2, y2;
2530         int k,l;
2531
2532         unsigned long pixel, blank;
2533
2534         term_data *td = (term_data*)(Term->data);
2535
2536         y *= Infofnt->hgt;
2537         x *= Infofnt->wid;
2538
2539         /* Add in affect of window boundaries */
2540         y += Infowin->oy;
2541         x += Infowin->ox;
2542
2543         for (i = 0; i < n; ++i, x += td->fnt->wid)
2544         {
2545                 a = *ap++;
2546                 c = *cp++;
2547
2548                 /* For extra speed - cache these values */
2549                 x1 = (c&0x7F) * td->fnt->twid;
2550                 y1 = (a&0x7F) * td->fnt->hgt;
2551
2552                 /* Illegal tile index */
2553                 if (td->tiles->width < x1 + td->fnt->wid ||
2554                     td->tiles->height < y1 + td->fnt->hgt)
2555                 {
2556                         /* Draw black square */
2557                         XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc,
2558                                        x, y, 
2559                                        td->fnt->twid, td->fnt->hgt);
2560
2561                         /* Skip drawing tile */
2562                         continue;
2563                 }
2564
2565                 ta = *tap++;
2566                 tc = *tcp++;
2567
2568                 /* For extra speed - cache these values */
2569                 x2 = (tc&0x7F) * td->fnt->twid;
2570                 y2 = (ta&0x7F) * td->fnt->hgt;
2571                 
2572                 /* Optimise the common case */
2573                 if (((x1 == x2) && (y1 == y2)) ||
2574                     !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
2575                     td->tiles->width < x2 + td->fnt->wid ||
2576                     td->tiles->height < y2 + td->fnt->hgt)
2577                 {
2578                         /* Draw object / terrain */
2579                         XPutImage(Metadpy->dpy, td->win->win,
2580                                 clr[0]->gc,
2581                                 td->tiles,
2582                                 x1, y1,
2583                                 x, y,
2584                                 td->fnt->twid, td->fnt->hgt);   
2585                 }
2586                 else
2587                 {
2588
2589                         /* Mega Hack^2 - assume the top left corner is "black" */
2590                         blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
2591
2592                         for (k = 0; k < td->fnt->twid; k++)
2593                         {
2594                                 for (l = 0; l < td->fnt->hgt; l++)
2595                                 {
2596                                         /* If mask set... */
2597                                         if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
2598                                         {
2599                                                 /* Output from the terrain */
2600                                                 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
2601                                         }
2602                                         
2603                                         /* Store into the temp storage. */
2604                                         XPutPixel(td->TmpImage, k, l, pixel);
2605                                 }
2606                         }
2607
2608
2609                         /* Draw to screen */
2610
2611                         XPutImage(Metadpy->dpy, td->win->win,
2612                               clr[0]->gc,
2613                              td->TmpImage,
2614                              0, 0, x, y,
2615                              td->fnt->twid, td->fnt->hgt);
2616                 }
2617         }
2618
2619         /* Redraw the selection if any, as it may have been obscured. (later) */
2620         s_ptr->drawn = FALSE;
2621
2622         /* Success */
2623         return (0);
2624 }
2625
2626 #ifdef USE_XIM
2627 static void IMDestroyCallback(XIM, XPointer, XPointer);
2628
2629 static void
2630 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
2631 {
2632         XIM xim;
2633         XIMCallback ximcallback;
2634         XIMStyles *xim_styles = NULL;
2635         int i;
2636
2637         /* Unused */
2638         (void)unused1;
2639         (void)unused2;
2640
2641         xim = XOpenIM(display, NULL, NULL, NULL);
2642         if(!xim){
2643                 printf("can't open IM\n");
2644                 return;
2645         }
2646
2647         /* initialize destroy callback */
2648         ximcallback.callback = IMDestroyCallback;
2649         ximcallback.client_data = NULL;
2650         XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
2651
2652         /* set style (only "Root" is supported yet...) */
2653         XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
2654         for (i = 0; i < xim_styles->count_styles; i++){
2655                 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
2656         }
2657         if(i >= xim_styles->count_styles){
2658                 printf("Sorry, your IM does not support 'Root' preedit style...\n");
2659                 XCloseIM(xim);
2660                 return;
2661         }
2662         XFree(xim_styles);
2663
2664         Metadpy->xim = xim;
2665
2666         for (i = 0; i < MAX_TERM_DATA; i++)
2667         {
2668                 infowin *iwin = data[i].win;
2669                 if (!iwin) continue;
2670                 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
2671                 if(!iwin->xic){
2672                         printf("Can't create input context for Term%d\n", i);
2673                         continue;
2674                 }
2675                 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL){
2676 /*                      printf("Can't get XNFilterEvents\n"); */
2677                         iwin->xic_mask = 0L;
2678                 }
2679                 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
2680         }
2681
2682         return;
2683 }
2684
2685 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
2686 {
2687         int i;
2688
2689         /* Unused */
2690         (void)xim;
2691         (void)client_data;
2692
2693         if (call_data == NULL){
2694                 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
2695         }
2696
2697         for(i = 0; i < MAX_TERM_DATA; i++)
2698         {
2699                 infowin *iwin = data[i].win;
2700                 if(!iwin) continue;
2701                 if(iwin->xic_mask){
2702                         XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
2703                         iwin->xic_mask = 0L;
2704                 }
2705                 iwin->xic = NULL;
2706         }
2707
2708         Metadpy->xim = NULL;
2709 }
2710 #endif
2711
2712 /*
2713  * Initialize a term_data
2714  */
2715 static errr term_data_init(term_data *td, int i)
2716 {
2717         term *t = &td->t;
2718
2719         concptr name = angband_term_name[i];
2720
2721         concptr font;
2722         int x = 0;
2723         int y = 0;
2724
2725         int cols = 80;
2726         int rows = 24;
2727
2728         int ox = 1;
2729         int oy = 1;
2730
2731         int wid, hgt, num;
2732
2733         char buf[80];
2734
2735         concptr str;
2736
2737         int val;
2738
2739         XClassHint *ch;
2740
2741         char res_name[20];
2742         char res_class[20];
2743
2744         XSizeHints *sh;
2745 #ifdef USE_XIM
2746         XWMHints *wh;
2747 #endif
2748
2749         /* Window specific font name */
2750         sprintf(buf, "ANGBAND_X11_FONT_%d", i);
2751
2752         /* Check environment for that font */
2753         font = getenv(buf);
2754
2755         /* Check environment for "base" font */
2756         if (!font) font = getenv("ANGBAND_X11_FONT");
2757
2758         /* No environment variables, use default font */
2759         if (!font)
2760         {
2761                 switch (i)
2762                 {
2763                         case 0:
2764                         {
2765                                 font = DEFAULT_X11_FONT_0;
2766                         }
2767                         break;
2768                         case 1:
2769                         {
2770                                 font = DEFAULT_X11_FONT_1;
2771                         }
2772                         break;
2773                         case 2:
2774                         {
2775                                 font = DEFAULT_X11_FONT_2;
2776                         }
2777                         break;
2778                         case 3:
2779                         {
2780                                 font = DEFAULT_X11_FONT_3;
2781                         }
2782                         break;
2783                         case 4:
2784                         {
2785                                 font = DEFAULT_X11_FONT_4;
2786                         }
2787                         break;
2788                         case 5:
2789                         {
2790                                 font = DEFAULT_X11_FONT_5;
2791                         }
2792                         break;
2793                         case 6:
2794                         {
2795                                 font = DEFAULT_X11_FONT_6;
2796                         }
2797                         break;
2798                         case 7:
2799                         {
2800                                 font = DEFAULT_X11_FONT_7;
2801                         }
2802                         break;
2803                         default:
2804                         {
2805                                 font = DEFAULT_X11_FONT;
2806                         }
2807                 }
2808         }
2809
2810         /* Window specific location (x) */
2811         sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
2812         str = getenv(buf);
2813         x = (str != NULL) ? atoi(str) : -1;
2814
2815         /* Window specific location (y) */
2816         sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
2817         str = getenv(buf);
2818         y = (str != NULL) ? atoi(str) : -1;
2819
2820
2821         /* Window specific cols */
2822         sprintf(buf, "ANGBAND_X11_COLS_%d", i);
2823         str = getenv(buf);
2824         val = (str != NULL) ? atoi(str) : -1;
2825         if (val > 0) cols = val;
2826
2827         /* Window specific rows */
2828         sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
2829         str = getenv(buf);
2830         val = (str != NULL) ? atoi(str) : -1;
2831         if (val > 0) rows = val;
2832
2833         /* Hack the main window must be at least 80x24 */
2834         if (!i)
2835         {
2836                 if (cols < 80) cols = 80;
2837                 if (rows < 24) rows = 24;
2838         }
2839
2840         /* Window specific inner border offset (ox) */
2841         sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
2842         str = getenv(buf);
2843         val = (str != NULL) ? atoi(str) : -1;
2844         if (val > 0) ox = val;
2845
2846         /* Window specific inner border offset (oy) */
2847         sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
2848         str = getenv(buf);
2849         val = (str != NULL) ? atoi(str) : -1;
2850         if (val > 0) oy = val;
2851
2852
2853         /* Prepare the standard font */
2854         MAKE(td->fnt, infofnt);
2855         Infofnt_set(td->fnt);
2856         Infofnt_init_data(font);
2857
2858         /* Hack -- key buffer size */
2859         num = ((i == 0) ? 1024 : 16);
2860
2861         /* Assume full size windows */
2862         wid = cols * td->fnt->wid + (ox + ox);
2863         hgt = rows * td->fnt->hgt + (oy + oy);
2864
2865         /* Create a top-window */
2866         MAKE(td->win, infowin);
2867         Infowin_set(td->win);
2868         Infowin_init_top(x, y, wid, hgt, 0,
2869                          Metadpy->fg, Metadpy->bg);
2870
2871         /* Ask for certain events */
2872 #if defined(USE_XIM)
2873         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
2874 #else
2875         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
2876 #endif
2877
2878         /* Set the window name */
2879         Infowin_set_name(name);
2880
2881         /* Save the inner border */
2882         Infowin->ox = ox;
2883         Infowin->oy = oy;
2884
2885         /* Make Class Hints */
2886         ch = XAllocClassHint();
2887
2888         if (ch == NULL) quit("XAllocClassHint failed");
2889
2890         strcpy(res_name, name);
2891         res_name[0] = FORCELOWER(res_name[0]);
2892         ch->res_name = res_name;
2893
2894         strcpy(res_class, "Angband");
2895         ch->res_class = res_class;
2896
2897         XSetClassHint(Metadpy->dpy, Infowin->win, ch);
2898
2899         /* Make Size Hints */
2900         sh = XAllocSizeHints();
2901
2902         /* Oops */
2903         if (sh == NULL) quit("XAllocSizeHints failed");
2904
2905         /* Main window has a differing minimum size */
2906         if (i == 0)
2907         {
2908                 /* Main window min size is 80x24 */
2909                 sh->flags = PMinSize | PMaxSize;
2910                 sh->min_width = 80 * td->fnt->wid + (ox + ox);
2911                 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
2912                 sh->max_width = 255 * td->fnt->wid + (ox + ox);
2913                 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
2914         }
2915
2916         /* Other windows can be shrunk to 1x1 */
2917         else
2918         {
2919                 /* Other windows */
2920                 sh->flags = PMinSize | PMaxSize;
2921                 sh->min_width = td->fnt->wid + (ox + ox);
2922                 sh->min_height = td->fnt->hgt + (oy + oy);
2923                 sh->max_width = 256 * td->fnt->wid + (ox + ox);
2924                 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
2925         }
2926
2927         /* Resize increment */
2928         sh->flags |= PResizeInc;
2929         sh->width_inc = td->fnt->wid;
2930         sh->height_inc = td->fnt->hgt;
2931
2932         /* Base window size */
2933         sh->flags |= PBaseSize;
2934         sh->base_width = (ox + ox);
2935         sh->base_height = (oy + oy);
2936
2937         /* Use the size hints */
2938         XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
2939
2940         /* Map the window */
2941         Infowin_map();
2942
2943 #ifdef USE_XIM
2944         /* Make WM Hints */
2945         wh = XAllocWMHints();
2946         if(wh == NULL) quit("XAllocWMHints failed");
2947         wh->flags = InputHint;
2948         wh->input = True;
2949         XSetWMHints(Metadpy->dpy, Infowin->win, wh);
2950 #endif
2951
2952         /* Move the window to requested location */
2953         if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
2954
2955
2956         /* Initialize the term */
2957         term_init(t, cols, rows, num);
2958
2959         /* Use a "soft" cursor */
2960         t->soft_cursor = TRUE;
2961
2962         /* Erase with "white space" */
2963         t->attr_blank = TERM_WHITE;
2964         t->char_blank = ' ';
2965
2966         /* Hooks */
2967         t->xtra_hook = Term_xtra_x11;
2968         t->curs_hook = Term_curs_x11;
2969         t->bigcurs_hook = Term_bigcurs_x11;
2970         t->wipe_hook = Term_wipe_x11;
2971         t->text_hook = Term_text_x11;
2972
2973         /* Save the data */
2974         t->data = td;
2975
2976         /* Activate (important) */
2977         Term_activate(t);
2978
2979         /* Success */
2980         return (0);
2981 }
2982
2983
2984 /*
2985  * Initialization function for an "X11" module to Angband
2986  */
2987 errr init_x11(int argc, char *argv[])
2988 {
2989         int i;
2990
2991         concptr dpy_name = "";
2992
2993         int num_term = 3;
2994
2995         char filename[1024];
2996
2997         int pict_wid = 0;
2998         int pict_hgt = 0;
2999
3000         char *TmpData;
3001
3002         /* Parse args */
3003         for (i = 1; i < argc; i++)
3004         {
3005                 if (prefix(argv[i], "-d"))
3006                 {
3007                         dpy_name = &argv[i][2];
3008                         continue;
3009                 }
3010                 
3011                 if (prefix(argv[i], "-s"))
3012                 {
3013                         smoothRescaling = FALSE;
3014                         continue;
3015                 }
3016
3017                 if (prefix(argv[i], "-a"))
3018                 {
3019                         arg_graphics = GRAPHICS_ADAM_BOLT;
3020                         continue;
3021                 }
3022
3023                 if (prefix(argv[i], "-o"))
3024                 {
3025                         arg_graphics = GRAPHICS_ORIGINAL;
3026                         continue;
3027                 }
3028
3029                 if (prefix(argv[i], "-b"))
3030                 {
3031                         arg_bigtile = use_bigtile = TRUE;
3032                         continue;
3033                 }
3034
3035                 if (prefix(argv[i], "-n"))
3036                 {
3037                         num_term = atoi(&argv[i][2]);
3038                         if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
3039                         else if (num_term < 1) num_term = 1;
3040                         continue;
3041                 }
3042
3043                 if (prefix(argv[i], "--"))
3044                 {
3045                         /* Ignore */
3046                         continue;
3047                 }
3048
3049                 plog_fmt("Ignoring option: %s", argv[i]);
3050         }
3051
3052 #ifdef USE_LOCALE
3053
3054 #ifdef JP
3055         /* Get locale information from environment variables */
3056         setlocale(LC_ALL, "");
3057
3058 #ifdef DEFAULT_LOCALE
3059         if(!strcmp(setlocale(LC_ALL, NULL), "C")){
3060                 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
3061                 setlocale(LC_ALL, DEFAULT_LOCALE);
3062         }
3063 #endif
3064
3065         if(!strcmp(setlocale(LC_ALL, NULL), "C"))
3066         {
3067                 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
3068         }
3069
3070         if(!XSupportsLocale()){
3071                 printf("can't support locale in X\n");
3072                 setlocale(LC_ALL, "C");
3073         }
3074 #else
3075         /* Set locale to "C" without using environment variables */
3076         setlocale(LC_ALL, "C");
3077 #endif /* JP */
3078
3079 #endif /* USE_LOCALE */
3080
3081
3082         /* Init the Metadpy if possible */
3083         if (Metadpy_init_name(dpy_name)) return (-1);
3084
3085
3086         /* Prepare cursor color */
3087         MAKE(xor, infoclr);
3088         Infoclr_set(xor);
3089         Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
3090
3091
3092         /* Prepare normal colors */
3093         for (i = 0; i < 256; ++i)
3094         {
3095                 Pixell pixel;
3096
3097                 MAKE(clr[i], infoclr);
3098
3099                 Infoclr_set(clr[i]);
3100
3101                 /* Acquire Angband colors */
3102                 color_table[i][0] = angband_color_table[i][0];
3103                 color_table[i][1] = angband_color_table[i][1];
3104                 color_table[i][2] = angband_color_table[i][2];
3105                 color_table[i][3] = angband_color_table[i][3];
3106
3107                 /* Default to monochrome */
3108                 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
3109
3110                 /* Handle color */
3111                 if (Metadpy->color)
3112                 {
3113                         /* Create pixel */
3114                         pixel = create_pixel(Metadpy->dpy,
3115                                              color_table[i][1],
3116                                              color_table[i][2],
3117                                              color_table[i][3]);
3118                 }
3119
3120                 /* Initialize the color */
3121                 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
3122         }
3123
3124
3125         /* Prepare required atoms. */
3126         set_atoms();
3127
3128
3129         /* Initialize the windows */
3130         for (i = 0; i < num_term; i++)
3131         {
3132                 term_data *td = &data[i];
3133
3134                 /* Initialize the term_data */
3135                 term_data_init(td, i);
3136
3137                 /* Save global entry */
3138                 angband_term[i] = Term;
3139         }
3140
3141         /* Raise the "Angband" window */
3142         Infowin_set(data[0].win);
3143         Infowin_raise();
3144
3145         /* Activate the "Angband" window screen */
3146         Term_activate(&data[0].t);
3147
3148 #ifdef USE_XIM
3149         {
3150                 char *p;
3151                 p = XSetLocaleModifiers("");
3152                 if(!p || !*p){
3153                         p = XSetLocaleModifiers("@im=");
3154                 }
3155 /*              printf("XMODIFIERS=\"%s\"\n", p); */
3156         }
3157         XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3158 #endif
3159
3160         /* initialize sound */
3161         if (arg_sound) init_sound();
3162
3163         /* Try graphics */
3164         switch (arg_graphics)
3165         {
3166         case GRAPHICS_ORIGINAL:
3167                 /* Try the "8x8.bmp" file */
3168                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
3169
3170                 /* Use the "8x8.bmp" file if it exists */
3171                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3172                 {
3173                         /* Use graphics */
3174                         use_graphics = TRUE;
3175
3176                         pict_wid = pict_hgt = 8;
3177
3178                         ANGBAND_GRAF = "old";
3179                         break;
3180                 }
3181                 /* Fall through */
3182
3183         case GRAPHICS_ADAM_BOLT:
3184                 /* Try the "16x16.bmp" file */
3185                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
3186
3187                 /* Use the "16x16.bmp" file if it exists */
3188                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3189                 {
3190                         /* Use graphics */
3191                         use_graphics = TRUE;
3192
3193                         pict_wid = pict_hgt = 16;
3194
3195                         ANGBAND_GRAF = "new";
3196
3197                         break;
3198                 }
3199         }
3200
3201         /* Load graphics */
3202         if (use_graphics)
3203         {
3204                 Display *dpy = Metadpy->dpy;
3205
3206                 XImage *tiles_raw;
3207
3208                 /* Load the graphical tiles */
3209                 tiles_raw = ReadBMP(dpy, filename);
3210
3211                 /* Initialize the windows */
3212                 for (i = 0; i < num_term; i++)
3213                 {
3214                         term_data *td = &data[i];
3215
3216                         term *t = &td->t;
3217
3218                         /* Graphics hook */
3219                         t->pict_hook = Term_pict_x11;
3220
3221                         /* Use graphics sometimes */
3222                         t->higher_pict = TRUE;
3223
3224                         /* Resize tiles */
3225                         td->tiles =
3226                         ResizeImage(dpy, tiles_raw,
3227                                     pict_wid, pict_hgt,
3228                                     td->fnt->twid, td->fnt->hgt);
3229                 }
3230
3231                 /* Initialize the transparency masks */
3232                 for (i = 0; i < num_term; i++)
3233                 {
3234                         term_data *td = &data[i];
3235                         int ii, jj;
3236                         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
3237                         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
3238                         int total;
3239
3240
3241                         /* Determine total bytes needed for image */
3242                         ii = 1;
3243                         jj = (depth - 1) >> 2;
3244                         while (jj >>= 1) ii <<= 1;
3245                         total = td->fnt->twid * td->fnt->hgt * ii;
3246                         
3247                         
3248                         TmpData = (char *)malloc(total);
3249
3250                         td->TmpImage = XCreateImage(dpy,visual,depth,
3251                                 ZPixmap, 0, TmpData,
3252                                 td->fnt->twid, td->fnt->hgt, 8, 0);
3253
3254                 }
3255
3256                 /* Free tiles_raw? XXX XXX */
3257         }
3258
3259         /* Success */
3260         return (0);
3261 }
3262
3263 #endif /* USE_X11 */