OSDN Git Service

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