OSDN Git Service

Suppress gcc warning
[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 USE_JP_FONTSTRUCT
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 USE_JP_FONTSTRUCT
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 USE_JP_FONTSTRUCT
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 USE_JP_FONTSTRUCT
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 USE_JP_FONTSTRUCT
1242         if (ikfnt->name)
1243         {
1244                 /* Free the name */
1245                 string_free(ikfnt->name);
1246         }
1247 #endif
1248
1249         /* Nuke info if needed */
1250         if (ifnt->nuke)
1251         {
1252                 /* Free the font */
1253 #ifdef USE_FONTSET
1254                 XFreeFontSet(Metadpy->dpy, ifnt->info);
1255 #else
1256                 XFreeFont(Metadpy->dpy, ifnt->info);
1257 #endif
1258         }
1259
1260 #ifdef USE_JP_FONTSTRUCT
1261         if (ikfnt->nuke)
1262         {
1263                 /* Free the font */
1264                 XFreeFont(Metadpy->dpy, ikfnt->info);
1265         }
1266 #endif
1267         /* Success */
1268         return (0);
1269 }
1270
1271 #endif /* IGNORE_UNUSED_FUNCTIONS */
1272
1273
1274 /*
1275  * Prepare a new 'infofnt'
1276  */
1277 #ifdef USE_JP_FONTSTRUCT
1278 static errr Infofnt_prepare(XFontStruct *info, XFontStruct *kinfo)
1279 #else
1280 #ifdef USE_FONTSET
1281 static errr Infofnt_prepare(XFontSet info)
1282 #else
1283 static errr Infofnt_prepare(XFontStruct *info)
1284 #endif
1285 #endif
1286
1287 {
1288         infofnt *ifnt = Infofnt;
1289
1290 #ifdef USE_JP_FONTSTRUCT
1291         infofnt *ikfnt = Infokfnt;
1292 #endif
1293         XCharStruct *cs;
1294 #ifdef USE_FONTSET
1295         XFontStruct **fontinfo;
1296         char **fontname;
1297         int n_fonts;
1298         int ascent, descent, width;
1299 #endif
1300
1301         /* Assign the struct */
1302         ifnt->info = info;
1303
1304 #ifdef USE_FONTSET
1305         n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);
1306
1307         ascent = descent = width = 0;
1308         while(n_fonts-- > 0){
1309                 cs = &((*fontinfo)->max_bounds);
1310                 if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
1311                 if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
1312                 if(((*fontinfo)->max_byte1) > 0){
1313                         /* Â¿¥Ð¥¤¥Èʸ»ú¤Î¾ì¹ç¤ÏÉýȾʬ(ü¿ôÀÚ¤ê¾å¤²)¤Çɾ²Á¤¹¤ë */
1314                         if(width < (cs->width+1)/2) width = (cs->width+1)/2;
1315                 }else{
1316                         if(width < cs->width) width = cs->width;
1317                 }
1318                 fontinfo++;
1319                 fontname++;
1320         }
1321         ifnt->asc = ascent;
1322         ifnt->hgt = ascent + descent;
1323         ifnt->wid = width;
1324 #else
1325         /* Jump into the max bouonds thing */
1326         cs = &(info->max_bounds);
1327
1328         /* Extract default sizing info */
1329         ifnt->asc = info->ascent;
1330         ifnt->hgt = info->ascent + info->descent;
1331         ifnt->wid = cs->width;
1332 #endif
1333
1334         if (use_bigtile)
1335                 ifnt->twid = 2 * ifnt->wid;
1336         else
1337                 ifnt->twid = ifnt->wid;
1338
1339 #ifdef USE_JP_FONTSTRUCT
1340     /* Assign the struct */
1341     ikfnt->info = kinfo;
1342  
1343     /* Jump into the max bouonds thing */
1344     cs = &(kinfo->max_bounds);
1345  
1346     /* Extract default sizing info */
1347     ikfnt->asc = kinfo->ascent;
1348     ikfnt->hgt = kinfo->ascent + kinfo->descent;
1349     ikfnt->wid = cs->width;
1350 #endif
1351 #ifndef JP
1352 #ifdef OBSOLETE_SIZING_METHOD
1353         /* Extract default sizing info */
1354         ifnt->asc = cs->ascent;
1355         ifnt->hgt = (cs->ascent + cs->descent);
1356         ifnt->wid = cs->width;
1357 #endif
1358 #endif
1359
1360         /* Success */
1361         return (0);
1362 }
1363
1364
1365 #ifndef IGNORE_UNUSED_FUNCTIONS
1366
1367 /*
1368  * Initialize a new 'infofnt'.
1369  */
1370 #ifdef USE_JP_FONTSTRUCT
1371 static errr Infofnt_init_real(XFontStruct *info, XFontStruct *kinfo)
1372 #else
1373 #ifdef USE_FONTSET
1374 static errr Infofnt_init_real(XFontSet info)
1375 #else
1376 static errr Infofnt_init_real(XFontStruct *info)
1377 #endif
1378 #endif
1379
1380 {
1381         /* Wipe the thing */
1382         (void)WIPE(Infofnt, infofnt);
1383
1384 #ifdef USE_JP_FONTSTRUCT
1385         WIPE(Infokfnt, infofnt);
1386 #endif
1387         /* No nuking */
1388         Infofnt->nuke = 0;
1389
1390 #ifdef USE_JP_FONTSTRUCT
1391         Infokfnt->nuke = 0;
1392 #endif
1393         /* Attempt to prepare it */
1394 #ifdef USE_JP_FONTSTRUCT
1395         return (Infofnt_prepare (info, kinfo));
1396 #else
1397         return (Infofnt_prepare(info));
1398 #endif
1399
1400 }
1401
1402 #endif /* IGNORE_UNUSED_FUNCTIONS */
1403
1404
1405 /*
1406  * Init an infofnt by its Name
1407  *
1408  * Inputs:
1409  *      name: The name of the requested Font
1410  */
1411 #ifdef USE_JP_FONTSTRUCT
1412 static void Infofnt_init_data(cptr name, cptr kname)
1413 #else
1414 static void Infofnt_init_data(cptr name)
1415 #endif
1416
1417 {
1418 #ifdef USE_FONTSET
1419         XFontSet info;
1420         char **missing_list;
1421         int missing_count;
1422         char *default_font;
1423 #else
1424         XFontStruct *info;
1425 #endif
1426
1427
1428 #ifdef USE_JP_FONTSTRUCT
1429         XFontStruct *kinfo;
1430 #endif
1431         /*** Load the info Fresh, using the name ***/
1432
1433         /* If the name is not given, report an error */
1434         if (!name || !*name) quit("Missing font!");
1435
1436 #ifdef USE_JP_FONTSTRUCT
1437         if (!kname || !*kname) quit("Missing kanji font!");
1438 #endif
1439         /* Attempt to load the font */
1440 #ifdef USE_FONTSET
1441         info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
1442         if(missing_count > 0){
1443                 printf("missing font(s): \n");
1444                 while(missing_count-- > 0){
1445                         printf("\t%s\n", missing_list[missing_count]);
1446                 }
1447                 XFreeStringList(missing_list);
1448         }
1449 #else
1450         info = XLoadQueryFont(Metadpy->dpy, name);
1451 #ifdef USE_JP_FONTSTRUCT
1452         kinfo = XLoadQueryFont(Metadpy->dpy, kname);
1453 #endif
1454 #endif
1455
1456
1457         /* The load failed, try to recover */
1458         if (!info) quit_fmt("Failed to find font:\"%s\"", name);
1459 #ifdef USE_JP_FONTSTRUCT
1460         if (!kinfo) quit_fmt("Failed to find font:\"%s\"", kname);
1461 #endif
1462
1463
1464
1465         /*** Init the font ***/
1466
1467         /* Wipe the thing */
1468         (void)WIPE(Infofnt, infofnt);
1469
1470 #ifdef USE_JP_FONTSTRUCT
1471         WIPE(Infokfnt, infofnt);
1472 #endif
1473         /* Attempt to prepare it */
1474 #ifdef USE_JP_FONTSTRUCT
1475         if (Infofnt_prepare(info, kinfo))
1476 #else
1477         if (Infofnt_prepare(info))
1478 #endif
1479
1480         {
1481                 /* Free the font */
1482 #ifdef USE_FONTSET
1483                 XFreeFontSet(Metadpy->dpy, info);
1484 #else
1485                 XFreeFont(Metadpy->dpy, info);
1486 #ifdef USE_JP_FONTSTRUCT
1487                 XFreeFont(Metadpy->dpy, kinfo);
1488 #endif
1489 #endif
1490                 /* Fail */
1491                 quit_fmt("Failed to prepare font:\"%s\"", name);
1492         }
1493
1494         /* Save a copy of the font name */
1495         Infofnt->name = string_make(name);
1496 #ifdef USE_JP_FONTSTRUCT
1497         Infokfnt->name = string_make(kname);
1498 #endif
1499
1500         /* Mark it as nukable */
1501         Infofnt->nuke = 1;
1502 #ifdef USE_JP_FONTSTRUCT
1503         Infokfnt->nuke = 1;
1504 #endif
1505 }
1506
1507
1508 #ifdef USE_JP_FONTSTRUCT
1509 /*
1510  * EUCÆüËܸ쥳¡¼¥É¤ò´Þ¤àʸ»úÎó¤òɽ¼¨¤¹¤ë (Xlib)
1511  */
1512 static void
1513 XDrawMultiString(display,d,gc, x, y, string, len, afont, 
1514       afont_width, afont_height, afont_ascent, kfont, kfont_width)
1515     Display *display;
1516     Drawable d;
1517     GC gc;
1518     int       x, y;
1519     char      *string;
1520     int len;
1521     XFontStruct *afont;
1522     int afont_width, afont_height, afont_ascent;
1523     XFontStruct *kfont;
1524     int kfont_width;
1525 {
1526     XChar2b       kanji[500];
1527     char *p;
1528     unsigned char *str;
1529     unsigned char *endp;
1530     int slen;
1531     str = string;
1532     endp = string + len;
1533
1534     while ( str < endp && *str ) {
1535
1536 #ifdef TOFU      
1537       if ( (*str) == 0x7f ) {
1538           
1539           /* 0x7F¤Ï¢£¤Ç·è¤áÂǤÁ */
1540           
1541           /* Ï¢Â³¤¹¤ë0x7F¤ÎŤµ¤ò¸¡½Ð */
1542           slen = 0;
1543           while ( str < endp && (*str) == 0x7f ) {
1544               slen++; 
1545               str++;
1546           }
1547           
1548           /* ÉÁ²è */
1549           XFillRectangle( display, d, gc, x, y-afont_ascent, 
1550                           slen * afont_width, afont_height);
1551  
1552           /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */
1553           x += afont_width * slen;
1554       } 
1555       else  
1556 #endif
1557       if ( iskanji(*str) ) {
1558           
1559           /* UJIS¤Î»Ï¤Þ¤ê */
1560           
1561           /* Ï¢Â³¤¹¤ëUJISʸ»ú¤ÎŤµ¤ò¸¡½Ð */
1562           slen = 0;
1563           while ( str < endp && *str && iskanji(*str) ) {
1564               kanji[slen].byte1 = *str++ & 0x7f;
1565               kanji[slen++].byte2 = *str++ & 0x7f;
1566           }
1567           
1568           /* ÉÁ²è */
1569           XSetFont( display, gc, kfont->fid );
1570           XDrawImageString16( display, d, gc, x, y, kanji, slen );
1571
1572  
1573           /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */
1574           x += kfont_width * slen;
1575           
1576       } else {
1577           
1578           /* Èó´Á»ú(=ASCII¤È²¾Äê)¤Î»Ï¤Þ¤ê */
1579           
1580           /* Ï¢Â³¤¹¤ëASCIIʸ»ú¤ò¸¡½Ð */
1581           p = str;
1582           slen = 0;
1583           while ( str < endp && *str && !iskanji(*str) ) {
1584 #ifdef TOFU
1585               if (*str == 0x7f)break;
1586 #endif
1587               str++;
1588               slen++;
1589           }
1590           
1591           /* ÉÁ²è */
1592           XSetFont( display, gc, afont->fid );
1593           XDrawImageString( display, d, gc, x, y, p, slen );
1594           
1595           /* ¥Ý¥¤¥ó¥¿¤ò¿Ê¤á¤ë */
1596           x += afont_width * slen;
1597       }
1598     }
1599 }
1600 #endif
1601
1602 /*
1603  * Standard Text
1604  */
1605 static errr Infofnt_text_std(int x, int y, cptr str, int len)
1606 {
1607         int i;
1608
1609
1610         /*** Do a brief info analysis ***/
1611
1612         /* Do nothing if the string is null */
1613         if (!str || !*str) return (-1);
1614
1615         /* Get the length of the string */
1616         if (len < 0) len = strlen(str);
1617
1618         /*** Decide where to place the string, vertically ***/
1619
1620         /* Ignore Vertical Justifications */
1621         y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
1622
1623
1624         /*** Decide where to place the string, horizontally ***/
1625
1626         /* Line up with x at left edge of column 'x' */
1627         x = (x * Infofnt->wid) + Infowin->ox;
1628
1629
1630         /*** Actually draw 'str' onto the infowin ***/
1631
1632 #ifndef USE_FONTSET
1633         /* Be sure the correct font is ready */
1634         XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1635 #endif
1636
1637         /*** Handle the fake mono we can enforce on fonts ***/
1638
1639         /* Monotize the font */
1640         if (Infofnt->mono)
1641         {
1642 #ifdef USE_JP_FONTSTRUCT
1643                 /* Be sure the correct font is ready */
1644                 XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1645 #endif
1646                 /* Do each character */
1647                 for (i = 0; i < len; ++i)
1648                 {
1649                         /* Note that the Infoclr is set up to contain the Infofnt */
1650                         XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1651                                          x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
1652                 }
1653         }
1654
1655         /* Assume monoospaced font */
1656         else
1657         {
1658                 /* Note that the Infoclr is set up to contain the Infofnt */
1659 #ifdef USE_JP_FONTSTRUCT
1660                 /* ´Á»ú¥Õ¥©¥ó¥È¤Îɽ¼¨Éý¤Ï ASCII¥Õ¥©¥ó¥È¤Î2Çܤ˸ÇÄê */
1661                 XDrawMultiString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1662                                  x, y, str, len,
1663                                  Infofnt->info, Infofnt->wid, Infofnt->hgt,
1664                                  Infofnt->asc, 
1665                                  Infokfnt->info, Infofnt->wid * 2);
1666 #else
1667 #ifdef USE_FONTSET
1668                 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
1669                                    Infoclr->gc, x, y, str, len);
1670 #else
1671                 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1672                                  x, y, str, len);
1673 #endif
1674 #endif
1675
1676         }
1677
1678
1679         /* Success */
1680         return (0);
1681 }
1682
1683
1684 /*
1685  * Painting where text would be
1686  */
1687 static errr Infofnt_text_non(int x, int y, cptr str, int len)
1688 {
1689         int w, h;
1690
1691
1692         /*** Find the width ***/
1693
1694         /* Negative length is a flag to count the characters in str */
1695         if (len < 0) len = strlen(str);
1696
1697         /* The total width will be 'len' chars * standard width */
1698         w = len * Infofnt->wid;
1699
1700
1701         /*** Find the X dimensions ***/
1702
1703         /* Line up with x at left edge of column 'x' */
1704         x = x * Infofnt->wid + Infowin->ox;
1705
1706
1707         /*** Find other dimensions ***/
1708
1709         /* Simply do 'Infofnt->hgt' (a single row) high */
1710         h = Infofnt->hgt;
1711
1712         /* Simply do "at top" in row 'y' */
1713         y = y * h + Infowin->oy;
1714
1715
1716         /*** Actually 'paint' the area ***/
1717
1718         /* Just do a Fill Rectangle */
1719         XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
1720
1721         /* Success */
1722         return (0);
1723 }
1724
1725
1726
1727 /*************************************************************************/
1728
1729
1730 /*
1731  * Angband specific code follows... (ANGBAND)
1732  */
1733
1734
1735 /*
1736  * Hack -- cursor color
1737  */
1738 static infoclr *xor;
1739
1740 /*
1741  * Actual color table
1742  */
1743 static infoclr *clr[256];
1744
1745 /*
1746  * Color info (unused, red, green, blue).
1747  */
1748 static byte color_table[256][4];
1749
1750 /*
1751  * Forward declare
1752  */
1753 typedef struct term_data term_data;
1754
1755 /*
1756  * A structure for each "term"
1757  */
1758 struct term_data
1759 {
1760         term t;
1761
1762         infofnt *fnt;
1763 #ifdef USE_JP_FONTSTRUCT
1764         infofnt *kfnt;
1765 #endif
1766
1767
1768         infowin *win;
1769
1770 #ifdef USE_GRAPHICS
1771
1772         XImage *tiles;
1773
1774         /* Tempory storage for overlaying tiles. */
1775         XImage *TmpImage;
1776
1777 #endif
1778
1779 };
1780
1781
1782 /*
1783  * The number of term data structures
1784  */
1785 #define MAX_TERM_DATA 8
1786
1787 /*
1788  * The array of term data structures
1789  */
1790 static term_data data[MAX_TERM_DATA];
1791
1792
1793 /* Use short names for the most commonly used elements of various structures. */
1794 #define DPY (Metadpy->dpy)
1795 #define WIN (Infowin->win)
1796
1797
1798 /* Describe a set of co-ordinates. */
1799 typedef struct co_ord co_ord;
1800 struct co_ord
1801 {
1802         int x;
1803         int y;
1804 };
1805
1806
1807 /*
1808  * A special structure to store information about the text currently
1809  * selected.
1810  */
1811 typedef struct x11_selection_type x11_selection_type;
1812 struct x11_selection_type
1813 {
1814         bool select; /* The selection is currently in use. */
1815         bool drawn; /* The selection is currently displayed. */
1816         term *t; /* The window where the selection is found. */
1817         co_ord init; /* The starting co-ordinates. */
1818         co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1819         co_ord old; /* The previous end co-ordinates. */
1820         Time time; /* The time at which the selection was finalised. */
1821 };
1822
1823 static x11_selection_type s_ptr[1];
1824
1825
1826 /*
1827  * Process a keypress event
1828  *
1829  * Also appears in "main-xaw.c".
1830  */
1831 static void react_keypress(XKeyEvent *xev)
1832 {
1833         int i, n, mc, ms, mo, mx;
1834
1835         uint ks1;
1836
1837         XKeyEvent *ev = (XKeyEvent*)(xev);
1838
1839         KeySym ks;
1840
1841         char buf[128];
1842         char msg[128];
1843
1844 #ifdef USE_XIM
1845         int valid_keysym = TRUE;
1846 #endif
1847
1848         /* Check for "normal" keypresses */
1849 #ifdef USE_XIM
1850         if(Focuswin && Focuswin->xic){
1851                 Status status;
1852                 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1853                 if(status == XBufferOverflow){
1854                         printf("Input is too long, and dropped\n");
1855                         return;
1856                 }
1857                 if(status != XLookupKeySym && status != XLookupBoth){
1858                         valid_keysym = FALSE;
1859                 }
1860         }else{
1861                 n = XLookupString(ev, buf, 125, &ks, NULL);
1862         }
1863 #else
1864         n = XLookupString(ev, buf, 125, &ks, NULL);
1865 #endif
1866
1867         /* Terminate */
1868         buf[n] = '\0';
1869
1870 #ifdef USE_XIM
1871         if(!valid_keysym){
1872                 /* Enqueue the normal key(s) */
1873                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1874
1875                 /* All done */
1876                 return;
1877         }
1878 #endif
1879
1880         /* Hack -- Ignore "modifier keys" */
1881         if (IsModifierKey(ks)) return;
1882
1883
1884         /* Hack -- convert into an unsigned int */
1885         ks1 = (uint)(ks);
1886
1887         /* Extract four "modifier flags" */
1888         mc = (ev->state & ControlMask) ? TRUE : FALSE;
1889         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1890         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1891         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1892
1893
1894         /* Normal keys with no modifiers */
1895         if (n && !mo && !mx && !IsSpecialKey(ks))
1896         {
1897                 /* Enqueue the normal key(s) */
1898                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1899
1900                 /* All done */
1901                 return;
1902         }
1903
1904
1905         /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1906         switch (ks1)
1907         {
1908                 case XK_Escape:
1909                 {
1910                         Term_keypress(ESCAPE);
1911                         return;
1912                 }
1913
1914                 case XK_Return:
1915                 {
1916                         Term_keypress('\r');
1917                         return;
1918                 }
1919
1920                 case XK_Tab:
1921                 {
1922                         Term_keypress('\t');
1923                         return;
1924                 }
1925
1926                 case XK_Delete:
1927                 {
1928                         Term_keypress(0x7f);
1929                         return;
1930                 }
1931                 case XK_BackSpace:
1932                 {
1933                         Term_keypress('\010');
1934                         return;
1935                 }
1936         }
1937
1938
1939         /* Hack -- Use the KeySym */
1940         if (ks)
1941         {
1942                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1943                         mc ? "N" : "", ms ? "S" : "",
1944                         mo ? "O" : "", mx ? "M" : "",
1945                         (unsigned long)(ks), 13);
1946         }
1947
1948         /* Hack -- Use the Keycode */
1949         else
1950         {
1951                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1952                         mc ? "N" : "", ms ? "S" : "",
1953                         mo ? "O" : "", mx ? "M" : "",
1954                         ev->keycode, 13);
1955         }
1956
1957         /* Enqueue the "macro trigger" string */
1958         for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1959
1960
1961         /* Hack -- auto-define macros as needed */
1962         if (n && (macro_find_exact(msg) < 0))
1963         {
1964                 /* Create a macro */
1965                 macro_add(msg, buf);
1966         }
1967 }
1968
1969
1970 /*
1971  * Find the square a particular pixel is part of.
1972  */
1973 static void pixel_to_square(int * const x, int * const y,
1974         const int ox, const int oy)
1975 {
1976         (*x) = (ox - Infowin->ox) / Infofnt->wid;
1977         (*y) = (oy - Infowin->oy) / Infofnt->hgt;
1978 }
1979
1980 /*
1981  * Find the pixel at the top-left corner of a square.
1982  */
1983 static void square_to_pixel(int * const x, int * const y,
1984         const int ox, const int oy)
1985 {
1986         (*x) = ox * Infofnt->wid + Infowin->ox;
1987         (*y) = oy * Infofnt->hgt + Infowin->oy;
1988 }
1989
1990 /*
1991  * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
1992  */
1993 static void sort_co_ord(co_ord *min, co_ord *max,
1994         const co_ord *b, const co_ord *a)
1995 {
1996         min->x = MIN(a->x, b->x);
1997         min->y = MIN(a->y, b->y);
1998         max->x = MAX(a->x, b->x);
1999         max->y = MAX(a->y, b->y);
2000 }
2001
2002 /*
2003  * Remove the selection by redrawing it.
2004  */
2005 static void mark_selection_clear(int x1, int y1, int x2, int y2)
2006 {
2007         Term_redraw_section(x1,y1,x2,y2);
2008 }
2009
2010 /*
2011  * Select an area by drawing a grey box around it.
2012  * NB. These two functions can cause flicker as the selection is modified,
2013  * as the game redraws the entire marked section.
2014  */
2015 static void mark_selection_mark(int x1, int y1, int x2, int y2)
2016 {
2017         square_to_pixel(&x1, &y1, x1, y1);
2018         square_to_pixel(&x2, &y2, x2, y2);
2019         XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
2020                 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
2021 }
2022
2023 /*
2024  * Mark a selection by drawing boxes around it (for now).
2025  */
2026 static void mark_selection(void)
2027 {
2028         co_ord min, max;
2029         term *old = Term;
2030         bool draw = s_ptr->select;
2031         bool clear = s_ptr->drawn;
2032
2033         /* Open the correct term if necessary. */
2034         if (s_ptr->t != old) Term_activate(s_ptr->t);
2035
2036         if (clear)
2037         {
2038                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
2039                 mark_selection_clear(min.x, min.y, max.x, max.y);
2040         }
2041         if (draw)
2042         {
2043                 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2044                 mark_selection_mark(min.x, min.y, max.x, max.y);
2045         }
2046
2047         /* Finish on the current term. */
2048         if (s_ptr->t != old) Term_activate(old);
2049
2050         s_ptr->old.x = s_ptr->cur.x;
2051         s_ptr->old.y = s_ptr->cur.y;
2052         s_ptr->drawn = s_ptr->select;
2053 }
2054
2055 /*
2056  * Forget a selection for one reason or another.
2057  */
2058 static void copy_x11_release(void)
2059 {
2060         /* Deselect the current selection. */
2061         s_ptr->select = FALSE;
2062
2063         /* Remove its graphical represesntation. */
2064         mark_selection();
2065 }
2066
2067 /*
2068  * Start to select some text on the screen.
2069  */
2070 static void copy_x11_start(int x, int y)
2071 {
2072         if (s_ptr->select) copy_x11_release();
2073
2074         /* Remember where the selection started. */
2075         s_ptr->t = Term;
2076         s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
2077         s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
2078 }
2079
2080 /*
2081  * Respond to movement of the mouse when selecting text.
2082  */
2083 static void copy_x11_cont(int x, int y, unsigned int buttons)
2084 {
2085         /* Use the nearest square within bounds if the mouse is outside. */
2086         x = MIN(MAX(x, 0), Term->wid-1);
2087         y = MIN(MAX(y, 0), Term->hgt-1);
2088
2089         /* The left mouse button isn't pressed. */
2090         if (~buttons & Button1Mask) return;
2091
2092         /* Not a selection in this window. */
2093         if (s_ptr->t != Term) return;
2094
2095         /* Not enough movement. */
2096         if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
2097
2098         /* Something is being selected. */
2099         s_ptr->select = TRUE;
2100
2101         /* Track the selection. */
2102         s_ptr->cur.x = x;
2103         s_ptr->cur.y = y;
2104
2105         /* Hack - display it inefficiently. */
2106         mark_selection();
2107 }
2108
2109 /*
2110  * Respond to release of the left mouse button by putting the selected text in
2111  * the primary buffer.
2112  */
2113 static void copy_x11_end(const Time time)
2114 {
2115         /* No selection. */
2116         if (!s_ptr->select) return;
2117
2118         /* Not a selection in this window. */
2119         if (s_ptr->t != Term) return;
2120
2121         /* Remember when the selection was finalised. */
2122         s_ptr->time = time;
2123
2124         /* Acquire the primary selection. */
2125         XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
2126         if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
2127         {
2128                 /* Failed to acquire the selection, so forget it. */
2129                 /* bell("Failed to acquire primary buffer."); */
2130                 s_ptr->select = FALSE;
2131                 mark_selection();
2132         }
2133 }
2134
2135
2136 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
2137
2138 /*
2139  * Set the required variable atoms at start-up to avoid errors later.
2140  */
2141 static void set_atoms(void)
2142 {
2143         xa_targets = XInternAtom(DPY, "TARGETS", False);
2144         xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
2145         xa_text = XInternAtom(DPY, "TEXT", False);
2146         xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
2147 }
2148
2149
2150 static Atom request_target = 0;
2151
2152 /*
2153  * Send a message to request that the PRIMARY buffer be sent here.
2154  */
2155 static void paste_x11_request(Atom target, const Time time)
2156 {
2157         /*
2158          * It's from some sample programs on the web.
2159          * What does it mean? -- XXX
2160          */
2161         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2162
2163         /* Check the owner. */
2164         if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
2165         {
2166                 /* No selection. */
2167                 /* bell("No selection found."); */
2168                 return;
2169         }
2170
2171         request_target = target;
2172     
2173         /* Request the event */
2174         XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
2175 }
2176
2177
2178 /*
2179  * Add the contents of the PRIMARY buffer to the input queue.
2180  *
2181  * Hack - This doesn't use the "time" of the event, and so accepts anything a
2182  * client tries to send it.
2183  */
2184 static void paste_x11_accept(const XSelectionEvent *ptr)
2185 {
2186         unsigned long left;
2187         const long offset = 0;
2188         const long length = 32000;
2189         XTextProperty xtextproperty;
2190         errr err = 0;
2191
2192         /*
2193          * It's from some sample programs on the web.
2194          * What does it mean? -- XXX
2195          */
2196         Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2197
2198
2199         /* Failure. */
2200         if (ptr->property == None)
2201         {
2202                 if (request_target == xa_compound_text)
2203                 {
2204                         /* Re-request as STRING */
2205                         paste_x11_request(XA_STRING, ptr->time);
2206                 }
2207                 else
2208                 {
2209                         request_target = 0;
2210                         plog("Paste failure (remote client could not send).");
2211                 }
2212                 return;
2213         }
2214
2215         if (ptr->selection != XA_PRIMARY)
2216         {
2217                 plog("Paste failure (remote client did not send primary selection).");
2218                 return;
2219         }
2220
2221         if (ptr->target != request_target)
2222         {
2223                 plog("Paste failure (selection in unknown format).");
2224                 return;
2225         }
2226
2227         /* Get text */
2228         if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
2229                                length, TRUE, request_target,
2230                                &xtextproperty.encoding,
2231                                &xtextproperty.format,
2232                                &xtextproperty.nitems,
2233                                &left,
2234                                &xtextproperty.value)
2235             != Success)
2236         {
2237                 /* Failure */
2238                 return;
2239         }
2240
2241         if (request_target == xa_compound_text)
2242         {
2243                 char **list;
2244                 int count;
2245                 
2246                 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
2247
2248                 if (list)
2249                 {
2250                         int i;
2251
2252                         for (i = 0; i < count; i++)
2253                         {
2254                                 /* Paste the text. */
2255                                 err = type_string(list[i], 0);
2256
2257                                 if (err) break;
2258                         }
2259
2260                         /* Free the string */
2261                         XFreeStringList(list);
2262                 }
2263         }
2264         else /* if (request_target == XA_STRING) */
2265         {
2266                 /* Paste the text. */
2267                 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
2268         }
2269
2270         /* Free the data pasted. */
2271         XFree(xtextproperty.value); 
2272
2273         /* No room. */
2274         if (err)
2275         {
2276                 plog("Paste failure (too much text selected).");
2277         }
2278 }
2279
2280
2281 /*
2282  * Add a character to a string in preparation for sending it to another
2283  * client as a STRING.
2284  * This doesn't change anything, as clients tend not to have difficulty in
2285  * receiving this format (although the standard specifies a restricted set).
2286  * Strings do not have a colour.
2287  */
2288 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
2289 {
2290         char buf[1024];
2291         char *list[1000];
2292         co_ord max, min;
2293         int x,y,l,n;
2294         byte a;
2295         char c;
2296
2297         /* Too old, or incorrect call. */
2298         if (rq->time < s_ptr->time) return FALSE;
2299
2300         /* Work out which way around to paste. */
2301         sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2302
2303         /* Paranoia. */
2304         if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
2305         {
2306                 /* bell("Someone stole my selection!"); */
2307                 return FALSE;
2308         }
2309
2310         /* Delete the old value of the property. */
2311         XDeleteProperty(DPY, rq->requestor, rq->property);
2312
2313         for (n = 0, y = 0; y < Term->hgt; y++)
2314         {
2315 #ifdef JP
2316                 int kanji = 0;
2317 #endif
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 #ifdef JP
2324                         if (x > max.x) break;
2325
2326                         /* Find the character. */
2327                         Term_what(x, y, &a, &c);
2328
2329                         if (1 == kanji) kanji = 2;
2330                         else if (iskanji(c)) kanji = 1;
2331                         else kanji = 0;
2332
2333                         if (x < min.x) continue;
2334
2335                         /*
2336                          * A single kanji character was divided in two...
2337                          * Delete the garbage.
2338                          */
2339                         if ((2 == kanji && x == min.x) ||
2340                             (1 == kanji && x == max.x))
2341                                 c = ' ';
2342 #else
2343                         if (x > max.x) break;
2344                         if (x < min.x) continue;
2345
2346                         /* Find the character. */
2347                         Term_what(x, y, &a, &c);
2348 #endif
2349
2350                         /* Add it. */
2351                         buf[l] = c;
2352                         l++;
2353                 }
2354
2355                 /* Ignore trailing spaces */
2356                 while (buf[l-1] == ' ') l--;
2357
2358                 /* Terminate all line unless it's single line. */
2359                 if (min.y != max.y)
2360                 {
2361                         buf[l] = '\n';
2362                         l++;
2363                 }
2364
2365                 /* End of string */
2366                 buf[l] = '\0';
2367
2368                 list[n++] = (char *)string_make(buf);
2369         }
2370
2371         /* End of the list */
2372         list[n] = NULL;
2373
2374
2375         if (rq->target == XA_STRING)
2376         {
2377                 for (n = 0; list[n]; n++)
2378                 {
2379                         /* Send the (non-empty) string. */
2380                         XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
2381                                         PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
2382                 }
2383         }
2384
2385         else if (rq->target == xa_text || 
2386                  rq->target == xa_compound_text)
2387         {
2388                 XTextProperty text_prop;
2389                 XICCEncodingStyle style;
2390
2391                 if (rq->target == xa_text)
2392                         style = XStdICCTextStyle;
2393                 else /* if (rq->target == xa_compound_text) */
2394                         style = XCompoundTextStyle;
2395
2396                 if (Success ==
2397                     XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
2398                 {
2399                         /* Send the compound text */
2400                         XChangeProperty(DPY,
2401                                         rq->requestor,
2402                                         rq->property,
2403                                         text_prop.encoding,
2404                                         text_prop.format,
2405                                         PropModeAppend,
2406                                         text_prop.value,
2407                                         text_prop.nitems);
2408                                 
2409                         /* Free the data. */
2410                         XFree(text_prop.value);
2411                 }
2412         }
2413
2414         /* Free the list of strings */
2415         for (n = 0; list[n]; n++)
2416         {
2417                 string_free(list[n]);
2418         }
2419
2420         return TRUE;
2421 }
2422
2423 /*
2424  * Send some text requested by another X client.
2425  */
2426 static void paste_x11_send(XSelectionRequestEvent *rq)
2427 {
2428         XEvent event;
2429         XSelectionEvent *ptr = &(event.xselection);
2430
2431         /* Set the event parameters. */
2432         ptr->type = SelectionNotify;
2433         ptr->property = rq->property;
2434         ptr->display = rq->display;
2435         ptr->requestor = rq->requestor;
2436         ptr->selection = rq->selection;
2437         ptr->target = rq->target;
2438         ptr->time = rq->time;
2439
2440         /* Paste the appropriate information for each target type.
2441          * Note that this currently rejects MULTIPLE targets.
2442          */
2443
2444         if (rq->target == XA_STRING ||
2445             rq->target == xa_text ||
2446             rq->target == xa_compound_text)
2447         {
2448                 if (!paste_x11_send_text(rq))
2449                         ptr->property = None;
2450         }
2451         else if (rq->target == xa_targets)
2452         {
2453                 Atom target_list[4];
2454                 target_list[0] = XA_STRING;
2455                 target_list[1] = xa_text;
2456                 target_list[2] = xa_compound_text;
2457                 target_list[3] = xa_targets;
2458                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2459                         (8 * sizeof(target_list[0])), PropModeReplace,
2460                         (unsigned char *)target_list,
2461                         (sizeof(target_list) / sizeof(target_list[0])));
2462         }
2463         else if (rq->target == xa_timestamp)
2464         {
2465                 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2466                         (8 * sizeof(Time)), PropModeReplace,
2467                         (unsigned char *)s_ptr->time, 1);
2468         }
2469         else
2470         {
2471                 ptr->property = None;
2472         }
2473
2474         /* Send whatever event we're left with. */
2475         XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
2476 }
2477
2478
2479 /*
2480  * Handle various events conditional on presses of a mouse button.
2481  */
2482 static void handle_button(Time time, int x, int y, int button,
2483         bool press)
2484 {
2485         /* The co-ordinates are only used in Angband format. */
2486         pixel_to_square(&x, &y, x, y);
2487
2488         if (press && button == 1) copy_x11_start(x, y);
2489         if (!press && button == 1) copy_x11_end(time);
2490         if (!press && button == 2) paste_x11_request(xa_compound_text, time);
2491 }
2492
2493
2494 /*
2495  * Process events
2496  */
2497 static errr CheckEvent(bool wait)
2498 {
2499         term_data *old_td = (term_data*)(Term->data);
2500
2501         XEvent xev_body, *xev = &xev_body;
2502
2503         term_data *td = NULL;
2504         infowin *iwin = NULL;
2505
2506         int i;
2507
2508 #ifdef USE_XIM
2509  redo_checkevent:
2510 #endif
2511
2512         /* Do not wait unless requested */
2513         if (!wait && !XPending(Metadpy->dpy)) return (1);
2514
2515         /*
2516          * Hack - redraw the selection, if needed.
2517          * This doesn't actually check that one of its squares was drawn to,
2518          * only that this may have happened.
2519          */
2520         if (s_ptr->select && !s_ptr->drawn) mark_selection();
2521
2522         /* Load the Event */
2523         XNextEvent(Metadpy->dpy, xev);
2524
2525 #ifdef USE_XIM
2526 /* #define DEBUG_EVENT */
2527 #ifdef DEBUG_EVENT
2528         {
2529                 printf("event: type=%d", xev->type);
2530                 switch(xev->type){
2531                 case KeyPress:
2532                         printf("(KeyPress), keycode=%X", xev->xkey.keycode);
2533                         break;
2534                 case FocusIn:
2535                         printf("(FocusIn)");
2536                         break;
2537                 case FocusOut:
2538                         printf("(FocusOut)");
2539                         break;
2540                 case ReparentNotify:
2541                         printf("(ReparentNotify)");
2542                         break;
2543                 case ConfigureNotify:
2544                         printf("(ConfigureNotify)");
2545                         break;
2546                 case MapNotify:
2547                         printf("(MapNotify)");
2548                         break;
2549                 case Expose:
2550                         printf("(Expose)");
2551                         break;
2552                 case ClientMessage:
2553                         printf("(ClientMessage)");
2554                         break;
2555                 }
2556                         
2557         }
2558 #endif
2559         if (XFilterEvent(xev, xev->xany.window)
2560                 /*XFilterEvent(xev, (data[0].win)->win)*/){
2561 #ifdef DEBUG_EVENT
2562                 printf(", [filtered by IM]\n");
2563 #endif
2564                 goto redo_checkevent;
2565         }
2566 #ifdef DEBUG_EVENT
2567         printf("\n");
2568 #endif
2569 #endif
2570
2571         /* Notice new keymaps */
2572         if (xev->type == MappingNotify)
2573         {
2574                 XRefreshKeyboardMapping(&xev->xmapping);
2575                 return 0;
2576         }
2577
2578
2579         /* Scan the windows */
2580         for (i = 0; i < MAX_TERM_DATA; i++)
2581         {
2582                 if (!data[i].win) continue;
2583                 if (xev->xany.window == data[i].win->win)
2584                 {
2585                         td = &data[i];
2586                         iwin = td->win;
2587                         break;
2588                 }
2589         }
2590
2591         /* Unknown window */
2592         if (!td || !iwin) return (0);
2593
2594
2595         /* Hack -- activate the Term */
2596         Term_activate(&td->t);
2597
2598         /* Hack -- activate the window */
2599         Infowin_set(iwin);
2600
2601
2602         /* Switch on the Type */
2603         switch (xev->type)
2604         {
2605                 case ButtonPress:
2606                 case ButtonRelease:
2607                 {
2608                         bool press = (xev->type == ButtonPress);
2609
2610                         /* Where is the mouse */
2611                         int x = xev->xbutton.x;
2612                         int y = xev->xbutton.y;
2613
2614                         int z;
2615
2616                         /* Which button is involved */
2617                         if (xev->xbutton.button == Button1) z = 1;
2618                         else if (xev->xbutton.button == Button2) z = 2;
2619                         else if (xev->xbutton.button == Button3) z = 3;
2620                         else if (xev->xbutton.button == Button4) z = 4;
2621                         else if (xev->xbutton.button == Button5) z = 5;
2622                         else z = 0;
2623
2624                         /* XXX Handle */
2625                         handle_button(xev->xbutton.time, x, y, z, press);
2626
2627                         break;
2628                 }
2629
2630                 case EnterNotify:
2631                 case LeaveNotify:
2632                 {
2633                         /* XXX Handle */
2634
2635                         break;
2636                 }
2637
2638                 case MotionNotify:
2639                 {
2640                         /* Where is the mouse */
2641                         int x = xev->xmotion.x;
2642                         int y = xev->xmotion.y;
2643                         unsigned int z = xev->xmotion.state;
2644
2645                         /* Convert to co-ordinates Angband understands. */
2646                         pixel_to_square(&x, &y, x, y);
2647
2648                         /* Highlight the current square, if appropriate. */
2649                         /* highlight_square(window, y, x); */
2650
2651                         /* Alter the selection if appropriate. */
2652                         copy_x11_cont(x, y, z);
2653
2654                         /* XXX Handle */
2655
2656                         break;
2657                 }
2658
2659                 case SelectionNotify:
2660                 {
2661                         paste_x11_accept(&(xev->xselection));
2662                         break;
2663                 }
2664
2665                 case SelectionRequest:
2666                 {
2667                         paste_x11_send(&(xev->xselectionrequest));
2668                         break;
2669                 }
2670
2671                 case SelectionClear:
2672                 {
2673                         s_ptr->select = FALSE;
2674                         mark_selection();
2675                         break;
2676                 }
2677
2678                 case KeyRelease:
2679                 {
2680                         /* Nothing */
2681                         break;
2682                 }
2683
2684                 case KeyPress:
2685                 {
2686                         /* Hack -- use "old" term */
2687                         Term_activate(&old_td->t);
2688
2689                         /* Process the key */
2690                         react_keypress(&(xev->xkey));
2691
2692                         break;
2693                 }
2694
2695                 case Expose:
2696                 {
2697                         int x1, x2, y1, y2;
2698                         
2699                         /* Ignore "extra" exposes */
2700                         /*if (xev->xexpose.count) break;*/
2701
2702                         /* Clear the window */
2703                         /*Infowin_wipe();*/
2704                         
2705                         x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
2706                         x2 = (xev->xexpose.x + xev->xexpose.width -
2707                                  Infowin->ox)/Infofnt->wid;
2708                         
2709                         y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
2710                         y2 = (xev->xexpose.y + xev->xexpose.height -
2711                                  Infowin->oy)/Infofnt->hgt;
2712                         
2713                         Term_redraw_section(x1, y1, x2, y2);
2714
2715                         /* Redraw */
2716                         /*Term_redraw();*/
2717
2718                         break;
2719                 }
2720
2721                 case MapNotify:
2722                 {
2723                         Infowin->mapped = 1;
2724                         Term->mapped_flag = TRUE;
2725                         break;
2726                 }
2727
2728                 case UnmapNotify:
2729                 {
2730                         Infowin->mapped = 0;
2731                         Term->mapped_flag = FALSE;
2732                         break;
2733                 }
2734
2735                 /* Move and/or Resize */
2736                 case ConfigureNotify:
2737                 {
2738                         int cols, rows, wid, hgt;
2739
2740                         int ox = Infowin->ox;
2741                         int oy = Infowin->oy;
2742
2743                         /* Save the new Window Parms */
2744                         Infowin->x = xev->xconfigure.x;
2745                         Infowin->y = xev->xconfigure.y;
2746                         Infowin->w = xev->xconfigure.width;
2747                         Infowin->h = xev->xconfigure.height;
2748
2749                         /* Determine "proper" number of rows/cols */
2750                         cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2751                         rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2752
2753                         /* Hack -- minimal size */
2754                         if (cols < 1) cols = 1;
2755                         if (rows < 1) rows = 1;
2756
2757                         if (td == &data[0])
2758                         {
2759                                 /* Hack the main window must be at least 80x24 */
2760                                 if (cols < 80) cols = 80;
2761                                 if (rows < 24) rows = 24;
2762                         }
2763
2764                         /* Desired size of window */
2765                         wid = cols * td->fnt->wid + (ox + ox);
2766                         hgt = rows * td->fnt->hgt + (oy + oy);
2767
2768                         /* Resize the Term (if needed) */
2769                         Term_resize(cols, rows);
2770
2771                         /* Resize the windows if any "change" is needed */
2772                         if ((Infowin->w != wid) || (Infowin->h != hgt))
2773                         {
2774                                 /* Resize window */
2775                                 Infowin_set(td->win);
2776                                 Infowin_resize(wid, hgt);
2777                         }
2778
2779                         break;
2780                 }
2781 #ifdef USE_XIM
2782                 case FocusIn:
2783                 {
2784                         if(iwin->xic){
2785                                 XSetICFocus(iwin->xic);
2786                         }
2787                         Focuswin = iwin;
2788                         break;
2789                 }
2790                 case FocusOut:
2791                 {
2792                         if(iwin->xic){
2793                                 XUnsetICFocus(iwin->xic);
2794                         }
2795                         /* Focuswin = NULL;*/
2796                         break;
2797                 }
2798 #endif
2799         }
2800
2801
2802         /* Hack -- Activate the old term */
2803         Term_activate(&old_td->t);
2804
2805         /* Hack -- Activate the proper window */
2806         Infowin_set(old_td->win);
2807
2808
2809         /* Success */
2810         return (0);
2811 }
2812
2813
2814 #ifdef USE_SOUND
2815
2816 /*
2817  * An array of sound file names
2818  */
2819 static cptr sound_file[SOUND_MAX];
2820
2821 /*
2822  * Check for existance of a file
2823  */
2824 static bool check_file(cptr s)
2825 {
2826         FILE *fff;
2827
2828         fff = fopen(s, "r");
2829         if (!fff) return (FALSE);
2830         
2831         fclose(fff);
2832         return (TRUE);
2833 }
2834
2835 /*
2836  * Initialize sound
2837  */
2838 static void init_sound(void)
2839 {
2840         int i;
2841         char wav[128];
2842         char buf[1024];
2843         char dir_xtra_sound[1024];
2844                 
2845         /* Build the "sound" path */
2846         path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
2847                 
2848         /* Prepare the sounds */
2849         for (i = 1; i < SOUND_MAX; i++)
2850         {
2851                 /* Extract name of sound file */
2852                 sprintf(wav, "%s.wav", angband_sound_name[i]);
2853                 
2854                 /* Access the sound */
2855                 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
2856                 
2857                 /* Save the sound filename, if it exists */
2858                 if (check_file(buf)) sound_file[i] = string_make(buf);
2859         }
2860         use_sound = TRUE;
2861         return;
2862 }
2863
2864 /*
2865  * Hack -- make a sound
2866  */
2867 static errr Term_xtra_x11_sound(int v)
2868 {
2869         char buf[1024];
2870         
2871         /* Sound disabled */
2872         if (!use_sound) return (1);
2873         
2874         /* Illegal sound */
2875         if ((v < 0) || (v >= SOUND_MAX)) return (1);
2876         
2877         /* Unknown sound */
2878         if (!sound_file[v]) return (1);
2879         
2880         sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
2881         
2882         return (system(buf) < 0);
2883         
2884 }
2885 #endif /* USE_SOUND */
2886
2887
2888 /*
2889  * Handle "activation" of a term
2890  */
2891 static errr Term_xtra_x11_level(int v)
2892 {
2893         term_data *td = (term_data*)(Term->data);
2894
2895         /* Handle "activate" */
2896         if (v)
2897         {
2898                 /* Activate the window */
2899                 Infowin_set(td->win);
2900
2901                 /* Activate the font */
2902                 Infofnt_set(td->fnt);
2903 #ifdef USE_JP_FONTSTRUCT
2904                 Infokfnt_set(td->kfnt);
2905 #endif
2906         }
2907
2908         /* Success */
2909         return (0);
2910 }
2911
2912
2913 /*
2914  * React to changes
2915  */
2916 static errr Term_xtra_x11_react(void)
2917 {
2918         int i;
2919         
2920         if (Metadpy->color)
2921         {
2922                 /* Check the colors */
2923                 for (i = 0; i < 256; i++)
2924                 {
2925                         if ((color_table[i][0] != angband_color_table[i][0]) ||
2926                             (color_table[i][1] != angband_color_table[i][1]) ||
2927                             (color_table[i][2] != angband_color_table[i][2]) ||
2928                             (color_table[i][3] != angband_color_table[i][3]))
2929                         {
2930                                 Pixell pixel;
2931
2932                                 /* Save new values */
2933                                 color_table[i][0] = angband_color_table[i][0];
2934                                 color_table[i][1] = angband_color_table[i][1];
2935                                 color_table[i][2] = angband_color_table[i][2];
2936                                 color_table[i][3] = angband_color_table[i][3];
2937
2938                                 /* Create pixel */
2939                                 pixel = create_pixel(Metadpy->dpy,
2940                                                      color_table[i][1],
2941                                                      color_table[i][2],
2942                                                      color_table[i][3]);
2943
2944                                 /* Change the foreground */
2945                                 Infoclr_set(clr[i]);
2946                                 Infoclr_change_fg(pixel);
2947                         }
2948                 }
2949         }
2950
2951         /* Success */
2952         return (0);
2953 }
2954
2955
2956 /*
2957  * Handle a "special request"
2958  */
2959 static errr Term_xtra_x11(int n, int v)
2960 {
2961         /* Handle a subset of the legal requests */
2962         switch (n)
2963         {
2964                 /* Make a noise */
2965                 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
2966
2967 #ifdef USE_SOUND
2968                 /* Make a special sound */
2969                 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
2970 #endif
2971
2972                 /* Flush the output XXX XXX */
2973                 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
2974
2975                 /* Process random events XXX */
2976                 case TERM_XTRA_BORED: return (CheckEvent(0));
2977
2978                 /* Process Events XXX */
2979                 case TERM_XTRA_EVENT: return (CheckEvent(v));
2980
2981                 /* Flush the events XXX */
2982                 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
2983
2984                 /* Handle change in the "level" */
2985                 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
2986
2987                 /* Clear the screen */
2988                 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
2989
2990                 /* Delay for some milliseconds */
2991                 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
2992
2993                 /* React to changes */
2994                 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
2995         }
2996
2997         /* Unknown */
2998         return (1);
2999 }
3000
3001
3002 /*
3003  * Draw the cursor as an inverted rectangle.
3004  *
3005  * Consider a rectangular outline like "main-mac.c".  XXX XXX
3006  */
3007 static errr Term_curs_x11(int x, int y)
3008 {
3009         if (use_graphics)
3010         {
3011                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3012                                x * Infofnt->wid + Infowin->ox,
3013                                y * Infofnt->hgt + Infowin->oy,
3014                                Infofnt->wid - 1, Infofnt->hgt - 1);
3015                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3016                                x * Infofnt->wid + Infowin->ox + 1,
3017                                y * Infofnt->hgt + Infowin->oy + 1,
3018                                Infofnt->wid - 3, Infofnt->hgt - 3);
3019         }
3020         else
3021         {
3022                 /* Draw the cursor */
3023                 Infoclr_set(xor);
3024
3025                 /* Hilite the cursor character */
3026                 Infofnt_text_non(x, y, " ", 1);
3027         }
3028
3029         /* Success */
3030         return (0);
3031 }
3032
3033
3034 /*
3035  * Draw the double width cursor
3036  */
3037 static errr Term_bigcurs_x11(int x, int y)
3038 {
3039         if (use_graphics)
3040         {
3041                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3042                                x * Infofnt->wid + Infowin->ox,
3043                                y * Infofnt->hgt + Infowin->oy,
3044                                Infofnt->twid - 1, Infofnt->hgt - 1);
3045                 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3046                                x * Infofnt->wid + Infowin->ox + 1,
3047                                y * Infofnt->hgt + Infowin->oy + 1,
3048                                Infofnt->twid - 3, Infofnt->hgt - 3);
3049         }
3050         else
3051         {
3052                 /* Draw the cursor */
3053                 Infoclr_set(xor);
3054
3055                 /* Hilite the cursor character */
3056                 Infofnt_text_non(x, y, "  ", 2);
3057         }
3058         /* Success */
3059         return (0);
3060 }
3061
3062
3063 /*
3064  * Erase some characters.
3065  */
3066 static errr Term_wipe_x11(int x, int y, int n)
3067 {
3068         /* Erase (use black) */
3069         Infoclr_set(clr[TERM_DARK]);
3070
3071         /* Mega-Hack -- Erase some space */
3072         Infofnt_text_non(x, y, "", n);
3073
3074         /* Redraw the selection if any, as it may have been obscured. (later) */
3075         s_ptr->drawn = FALSE;
3076
3077         /* Success */
3078         return (0);
3079 }
3080
3081
3082 /*
3083  * Draw some textual characters.
3084  */
3085 static errr Term_text_x11(int x, int y, int n, byte a, cptr s)
3086 {
3087         /* Draw the text */
3088         Infoclr_set(clr[a]);
3089
3090         /* Draw the text */
3091         Infofnt_text_std(x, y, s, n);
3092
3093         /* Redraw the selection if any, as it may have been obscured. (later) */
3094         s_ptr->drawn = FALSE;
3095
3096         /* Success */
3097         return (0);
3098 }
3099
3100
3101 #ifdef USE_GRAPHICS
3102
3103 /*
3104  * Draw some graphical characters.
3105  */
3106 static errr Term_pict_x11(int x, int y, int n, const byte *ap, const char *cp, const byte *tap, const char *tcp)
3107 {
3108         int i, x1, y1;
3109
3110         byte a;
3111         char c;
3112
3113         byte ta;
3114         char tc;
3115
3116         int x2, y2;
3117         int k,l;
3118
3119         unsigned long pixel, blank;
3120
3121         term_data *td = (term_data*)(Term->data);
3122
3123         y *= Infofnt->hgt;
3124         x *= Infofnt->wid;
3125
3126         /* Add in affect of window boundaries */
3127         y += Infowin->oy;
3128         x += Infowin->ox;
3129
3130         for (i = 0; i < n; ++i, x += td->fnt->wid)
3131         {
3132                 a = *ap++;
3133                 c = *cp++;
3134
3135                 /* For extra speed - cache these values */
3136                 x1 = (c&0x7F) * td->fnt->twid;
3137                 y1 = (a&0x7F) * td->fnt->hgt;
3138
3139                 /* Illegal tile index */
3140                 if (td->tiles->width < x1 + td->fnt->wid ||
3141                     td->tiles->height < y1 + td->fnt->hgt)
3142                 {
3143                         /* Draw black square */
3144                         XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc,
3145                                        x, y, 
3146                                        td->fnt->twid, td->fnt->hgt);
3147
3148                         /* Skip drawing tile */
3149                         continue;
3150                 }
3151
3152                 ta = *tap++;
3153                 tc = *tcp++;
3154
3155                 /* For extra speed - cache these values */
3156                 x2 = (tc&0x7F) * td->fnt->twid;
3157                 y2 = (ta&0x7F) * td->fnt->hgt;
3158                 
3159                 /* Optimise the common case */
3160                 if (((x1 == x2) && (y1 == y2)) ||
3161                     !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
3162                     td->tiles->width < x2 + td->fnt->wid ||
3163                     td->tiles->height < y2 + td->fnt->hgt)
3164                 {
3165                         /* Draw object / terrain */
3166                         XPutImage(Metadpy->dpy, td->win->win,
3167                                 clr[0]->gc,
3168                                 td->tiles,
3169                                 x1, y1,
3170                                 x, y,
3171                                 td->fnt->twid, td->fnt->hgt);   
3172                 }
3173                 else
3174                 {
3175
3176                         /* Mega Hack^2 - assume the top left corner is "black" */
3177                         blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
3178
3179                         for (k = 0; k < td->fnt->twid; k++)
3180                         {
3181                                 for (l = 0; l < td->fnt->hgt; l++)
3182                                 {
3183                                         /* If mask set... */
3184                                         if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
3185                                         {
3186                                                 /* Output from the terrain */
3187                                                 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
3188                                         }
3189                                         
3190                                         /* Store into the temp storage. */
3191                                         XPutPixel(td->TmpImage, k, l, pixel);
3192                                 }
3193                         }
3194
3195
3196                         /* Draw to screen */
3197
3198                         XPutImage(Metadpy->dpy, td->win->win,
3199                               clr[0]->gc,
3200                              td->TmpImage,
3201                              0, 0, x, y,
3202                              td->fnt->twid, td->fnt->hgt);
3203                 }
3204         }
3205
3206         /* Redraw the selection if any, as it may have been obscured. (later) */
3207         s_ptr->drawn = FALSE;
3208
3209         /* Success */
3210         return (0);
3211 }
3212
3213 #endif /* USE_GRAPHICS */
3214
3215 #ifdef USE_XIM
3216 static void IMDestroyCallback(XIM, XPointer, XPointer);
3217
3218 static void
3219 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
3220 {
3221         XIM xim;
3222         XIMCallback ximcallback;
3223         XIMStyles *xim_styles = NULL;
3224         int i;
3225
3226         /* Unused */
3227         (void)unused1;
3228         (void)unused2;
3229
3230         xim = XOpenIM(display, NULL, NULL, NULL);
3231         if(!xim){
3232                 printf("can't open IM\n");
3233                 return;
3234         }
3235
3236         /* initialize destroy callback */
3237         ximcallback.callback = IMDestroyCallback;
3238         ximcallback.client_data = NULL;
3239         XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
3240
3241         /* set style (only "Root" is supported yet...) */
3242         XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
3243         for (i = 0; i < xim_styles->count_styles; i++){
3244                 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
3245         }
3246         if(i >= xim_styles->count_styles){
3247                 printf("Sorry, your IM does not support 'Root' preedit style...\n");
3248                 XCloseIM(xim);
3249                 return;
3250         }
3251         XFree(xim_styles);
3252
3253         Metadpy->xim = xim;
3254
3255         for (i = 0; i < MAX_TERM_DATA; i++)
3256         {
3257                 infowin *iwin = data[i].win;
3258                 if (!iwin) continue;
3259                 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
3260                 if(!iwin->xic){
3261                         printf("Can't create input context for Term%d\n", i);
3262                         continue;
3263                 }
3264                 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL){
3265 /*                      printf("Can't get XNFilterEvents\n"); */
3266                         iwin->xic_mask = 0L;
3267                 }
3268                 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
3269         }
3270
3271         return;
3272 }
3273
3274 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
3275 {
3276         int i;
3277
3278         /* Unused */
3279         (void)xim;
3280         (void)client_data;
3281
3282         if (call_data == NULL){
3283                 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3284         }
3285
3286         for(i = 0; i < MAX_TERM_DATA; i++)
3287         {
3288                 infowin *iwin = data[i].win;
3289                 if(!iwin) continue;
3290                 if(iwin->xic_mask){
3291                         XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
3292                         iwin->xic_mask = 0L;
3293                 }
3294                 iwin->xic = NULL;
3295         }
3296
3297         Metadpy->xim = NULL;
3298 }
3299 #endif
3300
3301 /*
3302  * Initialize a term_data
3303  */
3304 static errr term_data_init(term_data *td, int i)
3305 {
3306         term *t = &td->t;
3307
3308         cptr name = angband_term_name[i];
3309
3310         cptr font;
3311 #ifdef USE_JP_FONTSTRUCT
3312         cptr kfont;
3313 #endif
3314
3315
3316         int x = 0;
3317         int y = 0;
3318
3319         int cols = 80;
3320         int rows = 24;
3321
3322         int ox = 1;
3323         int oy = 1;
3324
3325         int wid, hgt, num;
3326
3327         char buf[80];
3328
3329         cptr str;
3330
3331         int val;
3332
3333         XClassHint *ch;
3334
3335         char res_name[20];
3336         char res_class[20];
3337
3338         XSizeHints *sh;
3339 #ifdef USE_XIM
3340         XWMHints *wh;
3341 #endif
3342
3343         /* Window specific font name */
3344         sprintf(buf, "ANGBAND_X11_FONT_%d", i);
3345
3346         /* Check environment for that font */
3347         font = getenv(buf);
3348
3349         /* Check environment for "base" font */
3350         if (!font) font = getenv("ANGBAND_X11_FONT");
3351
3352         /* No environment variables, use default font */
3353         if (!font)
3354         {
3355                 switch (i)
3356                 {
3357                         case 0:
3358                         {
3359                                 font = DEFAULT_X11_FONT_0;
3360                         }
3361                         break;
3362                         case 1:
3363                         {
3364                                 font = DEFAULT_X11_FONT_1;
3365                         }
3366                         break;
3367                         case 2:
3368                         {
3369                                 font = DEFAULT_X11_FONT_2;
3370                         }
3371                         break;
3372                         case 3:
3373                         {
3374                                 font = DEFAULT_X11_FONT_3;
3375                         }
3376                         break;
3377                         case 4:
3378                         {
3379                                 font = DEFAULT_X11_FONT_4;
3380                         }
3381                         break;
3382                         case 5:
3383                         {
3384                                 font = DEFAULT_X11_FONT_5;
3385                         }
3386                         break;
3387                         case 6:
3388                         {
3389                                 font = DEFAULT_X11_FONT_6;
3390                         }
3391                         break;
3392                         case 7:
3393                         {
3394                                 font = DEFAULT_X11_FONT_7;
3395                         }
3396                         break;
3397                         default:
3398                         {
3399                                 font = DEFAULT_X11_FONT;
3400                         }
3401                 }
3402         }
3403
3404 #ifdef USE_JP_FONTSTRUCT
3405         /* Window specific font name */
3406         sprintf(buf, "ANGBAND_X11_KFONT_%d", i);
3407
3408         /* Check environment for that font */
3409         kfont = getenv(buf);
3410
3411         /* Check environment for "base" font */
3412         if (!kfont) kfont = getenv("ANGBAND_X11_KFONT");
3413
3414         /* No environment variables, use default font */
3415         if (!kfont)
3416         {
3417                 switch (i)
3418                 {
3419                         case 0:
3420                         {
3421                                 kfont = DEFAULT_X11_KFONT_0;
3422                         }
3423                         break;
3424                         case 1:
3425                         {
3426                                 kfont = DEFAULT_X11_KFONT_1;
3427                         }
3428                         break;
3429                         case 2:
3430                         {
3431                                 kfont = DEFAULT_X11_KFONT_2;
3432                         }
3433                         break;
3434                         case 3:
3435                         {
3436                                 kfont = DEFAULT_X11_KFONT_3;
3437                         }
3438                         break;
3439                         case 4:
3440                         {
3441                                 kfont = DEFAULT_X11_KFONT_4;
3442                         }
3443                         break;
3444                         case 5:
3445                         {
3446                                 kfont = DEFAULT_X11_KFONT_5;
3447                         }
3448                         break;
3449                         case 6:
3450                         {
3451                                 kfont = DEFAULT_X11_KFONT_6;
3452                         }
3453                         break;
3454                         case 7:
3455                         {
3456                                 kfont = DEFAULT_X11_KFONT_7;
3457                         }
3458                         break;
3459                         default:
3460                         {
3461                                 kfont = DEFAULT_X11_KFONT;
3462                         }
3463                 }
3464         }
3465 #endif
3466         /* Window specific location (x) */
3467         sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
3468         str = getenv(buf);
3469         x = (str != NULL) ? atoi(str) : -1;
3470
3471         /* Window specific location (y) */
3472         sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
3473         str = getenv(buf);
3474         y = (str != NULL) ? atoi(str) : -1;
3475
3476
3477         /* Window specific cols */
3478         sprintf(buf, "ANGBAND_X11_COLS_%d", i);
3479         str = getenv(buf);
3480         val = (str != NULL) ? atoi(str) : -1;
3481         if (val > 0) cols = val;
3482
3483         /* Window specific rows */
3484         sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
3485         str = getenv(buf);
3486         val = (str != NULL) ? atoi(str) : -1;
3487         if (val > 0) rows = val;
3488
3489         /* Hack the main window must be at least 80x24 */
3490         if (!i)
3491         {
3492                 if (cols < 80) cols = 80;
3493                 if (rows < 24) rows = 24;
3494         }
3495
3496         /* Window specific inner border offset (ox) */
3497         sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
3498         str = getenv(buf);
3499         val = (str != NULL) ? atoi(str) : -1;
3500         if (val > 0) ox = val;
3501
3502         /* Window specific inner border offset (oy) */
3503         sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
3504         str = getenv(buf);
3505         val = (str != NULL) ? atoi(str) : -1;
3506         if (val > 0) oy = val;
3507
3508
3509         /* Prepare the standard font */
3510 #ifdef USE_JP_FONTSTRUCT
3511         MAKE(td->fnt, infofnt);
3512         Infofnt_set(td->fnt);
3513         MAKE(td->kfnt, infofnt);
3514         Infokfnt_set(td->kfnt);
3515         Infofnt_init_data(font, kfont);
3516 #else
3517         MAKE(td->fnt, infofnt);
3518         Infofnt_set(td->fnt);
3519         Infofnt_init_data(font);
3520 #endif
3521
3522
3523         /* Hack -- key buffer size */
3524         num = ((i == 0) ? 1024 : 16);
3525
3526         /* Assume full size windows */
3527         wid = cols * td->fnt->wid + (ox + ox);
3528         hgt = rows * td->fnt->hgt + (oy + oy);
3529
3530         /* Create a top-window */
3531         MAKE(td->win, infowin);
3532         Infowin_set(td->win);
3533         Infowin_init_top(x, y, wid, hgt, 0,
3534                          Metadpy->fg, Metadpy->bg);
3535
3536         /* Ask for certain events */
3537 #if defined(USE_XIM)
3538         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
3539 #else
3540         Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
3541 #endif
3542
3543         /* Set the window name */
3544         Infowin_set_name(name);
3545
3546         /* Save the inner border */
3547         Infowin->ox = ox;
3548         Infowin->oy = oy;
3549
3550         /* Make Class Hints */
3551         ch = XAllocClassHint();
3552
3553         if (ch == NULL) quit("XAllocClassHint failed");
3554
3555         strcpy(res_name, name);
3556         res_name[0] = FORCELOWER(res_name[0]);
3557         ch->res_name = res_name;
3558
3559         strcpy(res_class, "Angband");
3560         ch->res_class = res_class;
3561
3562         XSetClassHint(Metadpy->dpy, Infowin->win, ch);
3563
3564         /* Make Size Hints */
3565         sh = XAllocSizeHints();
3566
3567         /* Oops */
3568         if (sh == NULL) quit("XAllocSizeHints failed");
3569
3570         /* Main window has a differing minimum size */
3571         if (i == 0)
3572         {
3573                 /* Main window min size is 80x24 */
3574                 sh->flags = PMinSize | PMaxSize;
3575                 sh->min_width = 80 * td->fnt->wid + (ox + ox);
3576                 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
3577                 sh->max_width = 255 * td->fnt->wid + (ox + ox);
3578                 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
3579         }
3580
3581         /* Other windows can be shrunk to 1x1 */
3582         else
3583         {
3584                 /* Other windows */
3585                 sh->flags = PMinSize | PMaxSize;
3586                 sh->min_width = td->fnt->wid + (ox + ox);
3587                 sh->min_height = td->fnt->hgt + (oy + oy);
3588                 sh->max_width = 256 * td->fnt->wid + (ox + ox);
3589                 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
3590         }
3591
3592         /* Resize increment */
3593         sh->flags |= PResizeInc;
3594         sh->width_inc = td->fnt->wid;
3595         sh->height_inc = td->fnt->hgt;
3596
3597         /* Base window size */
3598         sh->flags |= PBaseSize;
3599         sh->base_width = (ox + ox);
3600         sh->base_height = (oy + oy);
3601
3602         /* Use the size hints */
3603         XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
3604
3605         /* Map the window */
3606         Infowin_map();
3607
3608 #ifdef USE_XIM
3609         /* Make WM Hints */
3610         wh = XAllocWMHints();
3611         if(wh == NULL) quit("XAllocWMHints failed");
3612         wh->flags = InputHint;
3613         wh->input = True;
3614         XSetWMHints(Metadpy->dpy, Infowin->win, wh);
3615 #endif
3616
3617         /* Move the window to requested location */
3618         if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
3619
3620
3621         /* Initialize the term */
3622         term_init(t, cols, rows, num);
3623
3624         /* Use a "soft" cursor */
3625         t->soft_cursor = TRUE;
3626
3627         /* Erase with "white space" */
3628         t->attr_blank = TERM_WHITE;
3629         t->char_blank = ' ';
3630
3631         /* Hooks */
3632         t->xtra_hook = Term_xtra_x11;
3633         t->curs_hook = Term_curs_x11;
3634         t->bigcurs_hook = Term_bigcurs_x11;
3635         t->wipe_hook = Term_wipe_x11;
3636         t->text_hook = Term_text_x11;
3637
3638         /* Save the data */
3639         t->data = td;
3640
3641         /* Activate (important) */
3642         Term_activate(t);
3643
3644         /* Success */
3645         return (0);
3646 }
3647
3648
3649 /*
3650  * Initialization function for an "X11" module to Angband
3651  */
3652 errr init_x11(int argc, char *argv[])
3653 {
3654         int i;
3655
3656         cptr dpy_name = "";
3657
3658         int num_term = 3;
3659
3660 #ifdef USE_GRAPHICS
3661
3662         char filename[1024];
3663
3664         int pict_wid = 0;
3665         int pict_hgt = 0;
3666
3667         char *TmpData;
3668 #endif /* USE_GRAPHICS */
3669
3670
3671         /* Parse args */
3672         for (i = 1; i < argc; i++)
3673         {
3674                 if (prefix(argv[i], "-d"))
3675                 {
3676                         dpy_name = &argv[i][2];
3677                         continue;
3678                 }
3679                 
3680 #ifdef USE_GRAPHICS
3681                 if (prefix(argv[i], "-s"))
3682                 {
3683                         smoothRescaling = FALSE;
3684                         continue;
3685                 }
3686
3687                 if (prefix(argv[i], "-a"))
3688                 {
3689                         arg_graphics = GRAPHICS_ADAM_BOLT;
3690                         continue;
3691                 }
3692
3693                 if (prefix(argv[i], "-o"))
3694                 {
3695                         arg_graphics = GRAPHICS_ORIGINAL;
3696                         continue;
3697                 }
3698
3699                 if (prefix(argv[i], "-b"))
3700                 {
3701                         arg_bigtile = use_bigtile = TRUE;
3702                         continue;
3703                 }
3704 #endif /* USE_GRAPHICS */
3705
3706                 if (prefix(argv[i], "-n"))
3707                 {
3708                         num_term = atoi(&argv[i][2]);
3709                         if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
3710                         else if (num_term < 1) num_term = 1;
3711                         continue;
3712                 }
3713
3714                 if (prefix(argv[i], "--"))
3715                 {
3716                         /* Ignore */
3717                         continue;
3718                 }
3719
3720                 plog_fmt("Ignoring option: %s", argv[i]);
3721         }
3722
3723 #ifdef USE_LOCALE
3724
3725 #ifdef JP
3726         /* Get locale information from environment variables */
3727         setlocale(LC_ALL, "");
3728
3729 #ifdef DEFAULT_LOCALE
3730         if(!strcmp(setlocale(LC_ALL, NULL), "C")){
3731                 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
3732                 setlocale(LC_ALL, DEFAULT_LOCALE);
3733         }
3734 #endif
3735
3736         if(!strcmp(setlocale(LC_ALL, NULL), "C"))
3737         {
3738                 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
3739         }
3740
3741         if(!XSupportsLocale()){
3742                 printf("can't support locale in X\n");
3743                 setlocale(LC_ALL, "C");
3744         }
3745 #else
3746         /* Set locale to "C" without using environment variables */
3747         setlocale(LC_ALL, "C");
3748 #endif /* JP */
3749
3750 #endif /* USE_LOCALE */
3751
3752
3753         /* Init the Metadpy if possible */
3754         if (Metadpy_init_name(dpy_name)) return (-1);
3755
3756
3757         /* Prepare cursor color */
3758         MAKE(xor, infoclr);
3759         Infoclr_set(xor);
3760         Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
3761
3762
3763         /* Prepare normal colors */
3764         for (i = 0; i < 256; ++i)
3765         {
3766                 Pixell pixel;
3767
3768                 MAKE(clr[i], infoclr);
3769
3770                 Infoclr_set(clr[i]);
3771
3772                 /* Acquire Angband colors */
3773                 color_table[i][0] = angband_color_table[i][0];
3774                 color_table[i][1] = angband_color_table[i][1];
3775                 color_table[i][2] = angband_color_table[i][2];
3776                 color_table[i][3] = angband_color_table[i][3];
3777
3778                 /* Default to monochrome */
3779                 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
3780
3781                 /* Handle color */
3782                 if (Metadpy->color)
3783                 {
3784                         /* Create pixel */
3785                         pixel = create_pixel(Metadpy->dpy,
3786                                              color_table[i][1],
3787                                              color_table[i][2],
3788                                              color_table[i][3]);
3789                 }
3790
3791                 /* Initialize the color */
3792                 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
3793         }
3794
3795
3796         /* Prepare required atoms. */
3797         set_atoms();
3798
3799
3800         /* Initialize the windows */
3801         for (i = 0; i < num_term; i++)
3802         {
3803                 term_data *td = &data[i];
3804
3805                 /* Initialize the term_data */
3806                 term_data_init(td, i);
3807
3808                 /* Save global entry */
3809                 angband_term[i] = Term;
3810         }
3811
3812         /* Raise the "Angband" window */
3813         Infowin_set(data[0].win);
3814         Infowin_raise();
3815
3816         /* Activate the "Angband" window screen */
3817         Term_activate(&data[0].t);
3818
3819 #ifdef USE_XIM
3820         {
3821                 char *p;
3822                 p = XSetLocaleModifiers("");
3823                 if(!p || !*p){
3824                         p = XSetLocaleModifiers("@im=");
3825                 }
3826 /*              printf("XMODIFIERS=\"%s\"\n", p); */
3827         }
3828         XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3829 #endif
3830
3831 #ifdef USE_SOUND
3832         /* initialize sound */
3833         if (arg_sound) init_sound();
3834 #endif
3835
3836 #ifdef USE_GRAPHICS
3837
3838         /* Try graphics */
3839         switch (arg_graphics)
3840         {
3841         case GRAPHICS_ORIGINAL:
3842                 /* Try the "8x8.bmp" file */
3843                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
3844
3845                 /* Use the "8x8.bmp" file if it exists */
3846                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3847                 {
3848                         /* Use graphics */
3849                         use_graphics = TRUE;
3850
3851                         pict_wid = pict_hgt = 8;
3852
3853                         ANGBAND_GRAF = "old";
3854                         break;
3855                 }
3856                 /* Fall through */
3857
3858         case GRAPHICS_ADAM_BOLT:
3859                 /* Try the "16x16.bmp" file */
3860                 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
3861
3862                 /* Use the "16x16.bmp" file if it exists */
3863                 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3864                 {
3865                         /* Use graphics */
3866                         use_graphics = TRUE;
3867
3868                         pict_wid = pict_hgt = 16;
3869
3870                         ANGBAND_GRAF = "new";
3871
3872                         break;
3873                 }
3874         }
3875
3876         /* Load graphics */
3877         if (use_graphics)
3878         {
3879                 Display *dpy = Metadpy->dpy;
3880
3881                 XImage *tiles_raw;
3882
3883                 /* Load the graphical tiles */
3884                 tiles_raw = ReadBMP(dpy, filename);
3885
3886                 /* Initialize the windows */
3887                 for (i = 0; i < num_term; i++)
3888                 {
3889                         term_data *td = &data[i];
3890
3891                         term *t = &td->t;
3892
3893                         /* Graphics hook */
3894                         t->pict_hook = Term_pict_x11;
3895
3896                         /* Use graphics sometimes */
3897                         t->higher_pict = TRUE;
3898
3899                         /* Resize tiles */
3900                         td->tiles =
3901                         ResizeImage(dpy, tiles_raw,
3902                                     pict_wid, pict_hgt,
3903                                     td->fnt->twid, td->fnt->hgt);
3904                 }
3905
3906                 /* Initialize the transparency masks */
3907                 for (i = 0; i < num_term; i++)
3908                 {
3909                         term_data *td = &data[i];
3910                         int ii, jj;
3911                         int depth = DefaultDepth(dpy, DefaultScreen(dpy));
3912                         Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
3913                         int total;
3914
3915
3916                         /* Determine total bytes needed for image */
3917                         ii = 1;
3918                         jj = (depth - 1) >> 2;
3919                         while (jj >>= 1) ii <<= 1;
3920                         total = td->fnt->twid * td->fnt->hgt * ii;
3921                         
3922                         
3923                         TmpData = (char *)malloc(total);
3924
3925                         td->TmpImage = XCreateImage(dpy,visual,depth,
3926                                 ZPixmap, 0, TmpData,
3927                                 td->fnt->twid, td->fnt->hgt, 8, 0);
3928
3929                 }
3930
3931                 /* Free tiles_raw? XXX XXX */
3932         }
3933
3934 #endif /* USE_GRAPHICS */
3935
3936
3937         /* Success */
3938         return (0);
3939 }
3940
3941 #endif /* USE_X11 */
3942