OSDN Git Service

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