OSDN Git Service

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