OSDN Git Service

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