1 /* File: main-x11.c */
4 * Copyright (c) 1997 Ben Harrison, and others
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.
12 #ifdef USE_JP_FONTSTRUCT
14 * 日本語(EUC-JAPAN)対応 (-DJP)
16 * ・日本語を含む文字列の表示ルーチン XDrawMultiString() の追加
17 * ・日本語の表示幅は,フォントの情報によらすASCIIフォントの2倍に固定
22 * 1996/6/7 李 晃伸 (ri@kuis.kyoto-u.ac.jp)
26 * This file helps Angband work with UNIX/X11 computers.
28 * To use this file, compile with "USE_X11" defined, and link against all
29 * the various "X11" libraries which may be needed.
31 * See also "main-xaw.c".
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
39 * The rest of this file is an implementation of "main-xxx.c" for X11.
41 * Most of this file is by Ben Harrison (benh@phial.com).
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.
57 * echo "Launching angband..."
61 * setenv ANGBAND_X11_FONT_0 10x20
62 * setenv ANGBAND_X11_AT_X_0 5
63 * setenv ANGBAND_X11_AT_Y_0 510
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
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
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
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
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
97 * # The build directory
101 * setenv ANGBAND_X11_GAMMA 142
104 * ./src/angband -mx11 -- -n6 &
116 * Available graphic modes
118 #define GRAPHICS_NONE 0
119 #define GRAPHICS_ORIGINAL 1
120 #define GRAPHICS_ADAM_BOLT 2
121 #define GRAPHICS_HENGBAND 3
125 #ifndef __MAKEDEPEND__
126 #include <X11/Xlib.h>
127 #include <X11/Xutil.h>
128 #include <X11/keysym.h>
129 #include <X11/keysymdef.h>
131 #include <X11/Xlocale.h>
134 char *XSetIMValues(XIM, ...); /* Hack for XFree86 4.0 */
136 #include <X11/Xatom.h>
137 #endif /* __MAKEDEPEND__ */
141 * Include some helpful X11 code.
143 #include "maid-x11.c"
147 * Hack -- avoid some compiler warnings
149 #define IGNORE_UNUSED_FUNCTIONS
155 * 1) On a monochrome (or "fake-monochrome") display, all colors
156 * will be "cast" to "fg," except for the bg color, which is,
157 * obviously, cast to "bg". Thus, one can ignore this setting.
159 * 2) Because of the inner functioning of the color allocation
160 * routines, colors may be specified as (a) a typical color name,
161 * (b) a hexidecimal color specification (preceded by a pound sign),
162 * or (c) by strings such as "fg", "bg", "zg".
164 * 3) Due to the workings of the init routines, many colors
165 * may also be dealt with by their actual pixel values. Note that
166 * the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
167 * is not necessarily either black or white.
172 /**** Generic Types ****/
176 * An X11 pixell specifier
178 typedef unsigned long Pixell;
181 * The structures defined below
183 typedef struct metadpy metadpy;
184 typedef struct infowin infowin;
185 typedef struct infoclr infoclr;
186 typedef struct infofnt infofnt;
190 * A structure summarizing a given Display.
192 * - The Display itself
193 * - The default Screen for the display
194 * - The virtual root (usually just the root)
195 * - The default colormap (from a macro)
197 * - The "name" of the display
199 * - The socket to listen to for events
201 * - The width of the display screen (from a macro)
202 * - The height of the display screen (from a macro)
203 * - The bit depth of the display screen (from a macro)
205 * - The black Pixell (from a macro)
206 * - The white Pixell (from a macro)
208 * - The background Pixell (default: black)
209 * - The foreground Pixell (default: white)
210 * - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
212 * - Bit Flag: Force all colors to black and white (default: !color)
213 * - Bit Flag: Allow the use of color (default: depth > 1)
214 * - Bit Flag: We created 'dpy', and so should nuke it when done.
249 * A Structure summarizing Window Information.
251 * I assume that a window is at most 30000 pixels on a side.
252 * I assume that the root windw is also at most 30000 square.
255 * - The current Input Event Mask
257 * - The location of the window
258 * - The width, height of the window
259 * - The border width of this window
261 * - Byte: 1st Extra byte
263 * - Bit Flag: This window is currently Mapped
264 * - Bit Flag: This window needs to be redrawn
265 * - Bit Flag: This window has been resized
267 * - Bit Flag: We should nuke 'win' when done with it
269 * - Bit Flag: 1st extra flag
270 * - Bit Flag: 2nd extra flag
271 * - Bit Flag: 3rd extra flag
272 * - Bit Flag: 4th extra flag
310 * A Structure summarizing Operation+Color Information
312 * - The actual GC corresponding to this info
314 * - The Foreground Pixell Value
315 * - The Background Pixell Value
317 * - Num (0-15): The operation code (As in Clear, Xor, etc)
318 * - Bit Flag: The GC is in stipple mode
319 * - Bit Flag: Destroy 'gc' at Nuke time.
336 * A Structure to Hold Font Information
338 * - The 'XFontStruct*' (yields the 'Font')
342 * - The default character width
343 * - The default character height
344 * - The default character ascent
346 * - Byte: Pixel offset used during fake mono
348 * - Flag: Force monospacing via 'wid'
349 * - Flag: Nuke info when done
375 /**** Generic Macros ****/
379 /* Set current metadpy (Metadpy) to 'M' */
380 #define Metadpy_set(M) \
384 /* Initialize 'M' using Display 'D' */
385 #define Metadpy_init_dpy(D) \
386 Metadpy_init_2(D,cNULL)
388 /* Initialize 'M' using a Display named 'N' */
389 #define Metadpy_init_name(N) \
390 Metadpy_init_2((Display*)(NULL),N)
392 /* Initialize 'M' using the standard Display */
393 #define Metadpy_init() \
394 Metadpy_init_name("")
397 /* Init an infowin by giving father as an (info_win*) (or NULL), and data */
398 #define Infowin_init_dad(D,X,Y,W,H,B,FG,BG) \
399 Infowin_init_data(((D) ? ((D)->win) : (Window)(None)), \
403 /* Init a top level infowin by pos,size,bord,Colors */
404 #define Infowin_init_top(X,Y,W,H,B,FG,BG) \
405 Infowin_init_data(None,X,Y,W,H,B,FG,BG)
408 /* Request a new standard window by giving Dad infowin and X,Y,W,H */
409 #define Infowin_init_std(D,X,Y,W,H,B) \
410 Infowin_init_dad(D,X,Y,W,H,B,Metadpy->fg,Metadpy->bg)
413 /* Set the current Infowin */
414 #define Infowin_set(I) \
418 /* Set the current Infoclr */
419 #define Infoclr_set(C) \
423 #define Infoclr_init_ppo(F,B,O,M) \
424 Infoclr_init_data(F,B,O,M)
426 #define Infoclr_init_cco(F,B,O,M) \
427 Infoclr_init_ppo(Infoclr_Pixell(F),Infoclr_Pixell(B),O,M)
429 #define Infoclr_init_ppn(F,B,O,M) \
430 Infoclr_init_ppo(F,B,Infoclr_Opcode(O),M)
432 #define Infoclr_init_ccn(F,B,O,M) \
433 Infoclr_init_cco(F,B,Infoclr_Opcode(O),M)
436 /* Set the current infofnt */
437 #define Infofnt_set(I) \
441 /* Errr: Expose Infowin */
442 #define Infowin_expose() \
443 (!(Infowin->redraw = 1))
445 /* Errr: Unxpose Infowin */
446 #define Infowin_unexpose() \
447 (Infowin->redraw = 0)
451 /**** Generic Globals ****/
455 * The "default" values
457 static metadpy metadpy_default;
461 * The "current" variables
463 static metadpy *Metadpy = &metadpy_default;
464 static infowin *Infowin = (infowin*)(NULL);
466 static infowin *Focuswin = (infowin*)(NULL);
468 static infoclr *Infoclr = (infoclr*)(NULL);
469 #ifdef USE_JP_FONTSTRUCT
470 static infofnt *Infofnt = (infofnt*)(NULL);
471 static infofnt *Infokfnt = (infofnt*)(NULL);
473 static infofnt *Infofnt = (infofnt*)(NULL);
479 /**** Generic code ****/
482 #ifdef USE_JP_FONTSTRUCT
483 #define Infokfnt_set(I) \
487 * Init the current metadpy, with various initialization stuff.
490 * dpy: The Display* to use (if NULL, create it)
491 * name: The name of the Display (if NULL, the current)
494 * If 'name' is NULL, but 'dpy' is set, extract name from dpy
495 * If 'dpy' is NULL, then Create the named Display
496 * If 'name' is NULL, and so is 'dpy', use current Display
498 * Return -1 if no Display given, and none can be opened.
500 static errr Metadpy_init_2(Display *dpy, concptr name)
502 metadpy *m = Metadpy;
504 /*** Open the display if needed ***/
506 /* If no Display given, attempt to Create one */
509 /* Attempt to open the display */
510 dpy = XOpenDisplay(name);
513 if (!dpy) return (-1);
515 /* We will have to nuke it when done */
519 /* Since the Display was given, use it */
522 /* We will not have to nuke it when done */
527 /*** Save some information ***/
529 /* Save the Display itself */
532 /* Get the Screen and Virtual Root Window */
533 m->screen = DefaultScreenOfDisplay(dpy);
534 m->root = RootWindowOfScreen(m->screen);
536 /* Get the default colormap */
537 m->cmap = DefaultColormapOfScreen(m->screen);
539 /* Extract the true name of the display */
540 m->name = DisplayString(dpy);
543 m->fd = ConnectionNumber(Metadpy->dpy);
545 /* Save the Size and Depth of the screen */
546 m->width = WidthOfScreen(m->screen);
547 m->height = HeightOfScreen(m->screen);
548 m->depth = DefaultDepthOfScreen(m->screen);
550 /* Save the Standard Colors */
551 m->black = BlackPixelOfScreen(m->screen);
552 m->white = WhitePixelOfScreen(m->screen);
554 /*** Make some clever Guesses ***/
556 /* Guess at the desired 'fg' and 'bg' Pixell's */
560 /* Calculate the Maximum allowed Pixel value. */
561 m->zg = (1 << m->depth) - 1;
563 /* Save various default Flag Settings */
564 m->color = ((m->depth > 1) ? 1 : 0);
565 m->mono = ((m->color) ? 0 : 1);
567 /* Return "success" */
572 #ifndef IGNORE_UNUSED_FUNCTIONS
575 * Nuke the current metadpy
577 static errr Metadpy_nuke(void)
579 metadpy *m = Metadpy;
582 /* If required, Free the Display */
585 /* Close the Display */
586 XCloseDisplay(m->dpy);
588 /* Forget the Display */
589 m->dpy = (Display*)(NULL);
591 /* Do not nuke it again */
599 #endif /* IGNORE_UNUSED_FUNCTIONS */
603 * General Flush/ Sync/ Discard routine
605 static errr Metadpy_update(int flush, int sync, int discard)
607 /* Flush if desired */
608 if (flush) XFlush(Metadpy->dpy);
610 /* Sync if desired, using 'discard' */
611 if (sync) XSync(Metadpy->dpy, discard);
621 static errr Metadpy_do_beep(void)
623 /* Make a simple beep */
624 XBell(Metadpy->dpy, 100);
632 * Set the name (in the title bar) of Infowin
634 static errr Infowin_set_name(concptr name)
641 st = XStringListToTextProperty(&bp, 1, &tp);
642 if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
647 #ifndef IGNORE_UNUSED_FUNCTIONS
650 * Set the icon name of Infowin
652 static errr Infowin_set_icon_name(concptr name)
659 st = XStringListToTextProperty(&bp, 1, &tp);
660 if (st) XSetWMIconName(Metadpy->dpy, Infowin->win, &tp);
668 static errr Infowin_nuke(void)
670 infowin *iwin = Infowin;
672 /* Nuke if requested */
675 /* Destory the old window */
676 XDestroyWindow(Metadpy->dpy, iwin->win);
683 #endif /* IGNORE_UNUSED_FUNCTIONS */
687 * Prepare a new 'infowin'.
689 static errr Infowin_prepare(Window xid)
691 infowin *iwin = Infowin;
694 XWindowAttributes xwa;
696 unsigned int w, h, b, d;
701 /* Check For Error XXX Extract some ACTUAL data from 'xid' */
702 XGetGeometry(Metadpy->dpy, xid, &tmp_win, &x, &y, &w, &h, &b, &d);
704 /* Apply the above info */
711 /* Check Error XXX Extract some more ACTUAL data */
712 XGetWindowAttributes(Metadpy->dpy, xid, &xwa);
714 /* Apply the above info */
715 iwin->mask = xwa.your_event_mask;
716 iwin->mapped = ((xwa.map_state == IsUnmapped) ? 0 : 1);
718 /* And assume that we are exposed */
726 #ifndef IGNORE_UNUSED_FUNCTIONS
729 * Initialize a new 'infowin'.
731 static errr Infowin_init_real(Window xid)
734 (void)WIPE(Infowin, infowin);
736 /* Start out non-nukable */
739 /* Attempt to Prepare ourself */
740 return (Infowin_prepare(xid));
743 #endif /* IGNORE_UNUSED_FUNCTIONS */
747 * Init an infowin by giving some data.
750 * dad: The Window that should own this Window (if any)
751 * x,y: The position of this Window
752 * w,h: The size of this Window
753 * b,d: The border width and pixel depth
756 * If 'dad == None' assume 'dad == root'
758 static errr Infowin_init_data(Window dad, int x, int y, int w, int h,
759 int b, Pixell fg, Pixell bg)
764 (void)WIPE(Infowin, infowin);
767 /*** Error Check XXX ***/
770 /*** Create the Window 'xid' from data ***/
772 /* What happened here? XXX XXX XXX */
774 /* If no parent given, depend on root */
777 /* #ifdef USE_GRAPHICS
779 xid = XCreateWindow(Metadpy->dpy, Metadpy->root, x, y, w, h, b, 8, InputOutput, CopyFromParent, 0, 0);
790 /* Create the Window XXX Error Check */
791 xid = XCreateSimpleWindow(Metadpy->dpy, dad, x, y, w, h, b, fg, bg);
793 /* Start out selecting No events */
794 XSelectInput(Metadpy->dpy, xid, 0L);
797 /*** Prepare the new infowin ***/
799 /* Mark it as nukable */
802 /* Attempt to Initialize the infowin */
803 return (Infowin_prepare(xid));
809 * Modify the event mask of an Infowin
811 static errr Infowin_set_mask(long mask)
813 /* Save the new setting */
814 Infowin->mask = mask;
816 /* Execute the Mapping */
817 XSelectInput(Metadpy->dpy, Infowin->win, Infowin->mask);
825 * Request that Infowin be mapped
827 static errr Infowin_map(void)
829 /* Execute the Mapping */
830 XMapWindow(Metadpy->dpy, Infowin->win);
837 #ifndef IGNORE_UNUSED_FUNCTIONS
840 * Request that Infowin be unmapped
842 static errr Infowin_unmap(void)
844 /* Execute the Un-Mapping */
845 XUnmapWindow(Metadpy->dpy, Infowin->win);
851 #endif /* IGNORE_UNUSED_FUNCTIONS */
855 * Request that Infowin be raised
857 static errr Infowin_raise(void)
859 /* Raise towards visibility */
860 XRaiseWindow(Metadpy->dpy, Infowin->win);
867 #ifndef IGNORE_UNUSED_FUNCTIONS
870 * Request that Infowin be lowered
872 static errr Infowin_lower(void)
874 /* Lower towards invisibility */
875 XLowerWindow(Metadpy->dpy, Infowin->win);
881 #endif /* IGNORE_UNUSED_FUNCTIONS */
885 * Request that Infowin be moved to a new location
887 static errr Infowin_impell(int x, int y)
889 /* Execute the request */
890 XMoveWindow(Metadpy->dpy, Infowin->win, x, y);
900 static errr Infowin_resize(int w, int h)
902 /* Execute the request */
903 XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
910 #ifndef IGNORE_UNUSED_FUNCTIONS
913 * Move and Resize an infowin
915 static errr Infowin_locate(int x, int y, int w, int h)
917 /* Execute the request */
918 XMoveResizeWindow(Metadpy->dpy, Infowin->win, x, y, w, h);
924 #endif /* IGNORE_UNUSED_FUNCTIONS */
928 * Visually clear Infowin
930 static errr Infowin_wipe(void)
932 /* Execute the request */
933 XClearWindow(Metadpy->dpy, Infowin->win);
940 #ifndef IGNORE_UNUSED_FUNCTIONS
943 * Visually Paint Infowin with the current color
945 static errr Infowin_fill(void)
947 /* Execute the request */
948 XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc,
949 0, 0, Infowin->w, Infowin->h);
955 #endif /* IGNORE_UNUSED_FUNCTIONS */
959 * A NULL terminated pair list of legal "operation names"
961 * Pairs of values, first is texttual name, second is the string
962 * holding the decimal value that the operation corresponds to.
964 static concptr opcode_pairs[] =
983 "+copyInverted", "12",
991 * Parse a word into an operation "code"
994 * str: A string, hopefully representing an Operation
997 * 0-15: if 'str' is a valid Operation
998 * -1: if 'str' could not be parsed
1000 static int Infoclr_Opcode(concptr str)
1004 /* Scan through all legal operation names */
1005 for (i = 0; opcode_pairs[i*2]; ++i)
1007 /* Is this the right oprname? */
1008 if (streq(opcode_pairs[i*2], str))
1010 /* Convert the second element in the pair into a Code */
1011 return (atoi(opcode_pairs[i*2+1]));
1015 /* The code was not found, return -1 */
1020 #ifndef IGNORE_UNUSED_FUNCTIONS
1023 * Request a Pixell by name. Note: uses 'Metadpy'.
1026 * name: The name of the color to try to load (see below)
1029 * The Pixell value that metched the given name
1030 * 'Metadpy->fg' if the name was unparseable
1032 * Valid forms for 'name':
1033 * 'fg', 'bg', 'zg', '<name>' and '#<code>'
1035 static Pixell Infoclr_Pixell(concptr name)
1039 /* Attempt to Parse the name */
1040 if (name && name[0])
1042 /* The 'bg' color is available */
1043 if (streq(name, "bg")) return (Metadpy->bg);
1045 /* The 'fg' color is available */
1046 if (streq(name, "fg")) return (Metadpy->fg);
1048 /* The 'zg' color is available */
1049 if (streq(name, "zg")) return (Metadpy->zg);
1051 /* The 'white' color is available */
1052 if (streq(name, "white")) return (Metadpy->white);
1054 /* The 'black' color is available */
1055 if (streq(name, "black")) return (Metadpy->black);
1057 /* Attempt to parse 'name' into 'scrn' */
1058 if (!(XParseColor(Metadpy->dpy, Metadpy->cmap, name, &scrn)))
1060 plog_fmt("Warning: Couldn't parse color '%s'\n", name);
1063 /* Attempt to Allocate the Parsed color */
1064 if (!(XAllocColor(Metadpy->dpy, Metadpy->cmap, &scrn)))
1066 plog_fmt("Warning: Couldn't allocate color '%s'\n", name);
1069 /* The Pixel was Allocated correctly */
1070 else return (scrn.pixel);
1073 /* Warn about the Default being Used */
1074 plog_fmt("Warning: Using 'fg' for unknown color '%s'\n", name);
1076 /* Default to the 'Foreground' color */
1077 return (Metadpy->fg);
1082 * Initialize a new 'infoclr' with a real GC.
1084 static errr Infoclr_init_1(GC gc)
1086 infoclr *iclr = Infoclr;
1088 /* Wipe the iclr clean */
1089 (void)WIPE(iclr, infoclr);
1100 * Nuke an old 'infoclr'.
1102 static errr Infoclr_nuke(void)
1104 infoclr *iclr = Infoclr;
1106 /* Deal with 'GC' */
1110 XFreeGC(Metadpy->dpy, iclr->gc);
1113 /* Forget the current */
1114 Infoclr = (infoclr*)(NULL);
1120 #endif /* IGNORE_UNUSED_FUNCTIONS */
1124 * Initialize an infoclr with some data
1127 * fg: The Pixell for the requested Foreground (see above)
1128 * bg: The Pixell for the requested Background (see above)
1129 * op: The Opcode for the requested Operation (see above)
1130 * stip: The stipple mode
1132 static errr Infoclr_init_data(Pixell fg, Pixell bg, int op, int stip)
1134 infoclr *iclr = Infoclr;
1138 unsigned long gc_mask;
1142 /*** Simple error checking of opr and clr ***/
1144 /* Check the 'Pixells' for realism */
1145 if (bg > Metadpy->zg) return (-1);
1146 if (fg > Metadpy->zg) return (-1);
1148 /* Check the data for trueness */
1149 if ((op < 0) || (op > 15)) return (-1);
1152 /*** Create the requested 'GC' ***/
1154 /* Assign the proper GC function */
1157 /* Assign the proper GC background */
1158 gcv.background = bg;
1160 /* Assign the proper GC foreground */
1161 gcv.foreground = fg;
1163 /* Hack -- Handle XOR (xor is code 6) by hacking bg and fg */
1164 if (op == 6) gcv.background = 0;
1165 if (op == 6) gcv.foreground = (bg ^ fg);
1167 /* Assign the proper GC Fill Style */
1168 gcv.fill_style = (stip ? FillStippled : FillSolid);
1170 /* Turn off 'Give exposure events for pixmap copying' */
1171 gcv.graphics_exposures = False;
1173 /* Set up the GC mask */
1174 gc_mask = (GCFunction | GCBackground | GCForeground |
1175 GCFillStyle | GCGraphicsExposures);
1177 /* Create the GC detailed above */
1178 gc = XCreateGC(Metadpy->dpy, Metadpy->root, gc_mask, &gcv);
1181 /*** Initialize ***/
1183 /* Wipe the iclr clean */
1184 (void)WIPE(iclr, infoclr);
1189 /* Nuke it when done */
1192 /* Assign the parms */
1196 iclr->stip = stip ? 1 : 0;
1205 * Change the 'fg' for an infoclr
1208 * fg: The Pixell for the requested Foreground (see above)
1210 static errr Infoclr_change_fg(Pixell fg)
1212 infoclr *iclr = Infoclr;
1215 /*** Simple error checking of opr and clr ***/
1217 /* Check the 'Pixells' for realism */
1218 if (fg > Metadpy->zg) return (-1);
1224 XSetForeground(Metadpy->dpy, iclr->gc, fg);
1232 #ifndef IGNORE_UNUSED_FUNCTIONS
1235 * Nuke an old 'infofnt'.
1237 static errr Infofnt_nuke(void)
1239 infofnt *ifnt = Infofnt;
1241 #ifdef USE_JP_FONTSTRUCT
1242 infofnt *ikfnt = Infokfnt;
1244 /* Deal with 'name' */
1248 string_free(ifnt->name);
1251 #ifdef USE_JP_FONTSTRUCT
1255 string_free(ikfnt->name);
1259 /* Nuke info if needed */
1264 XFreeFontSet(Metadpy->dpy, ifnt->info);
1266 XFreeFont(Metadpy->dpy, ifnt->info);
1270 #ifdef USE_JP_FONTSTRUCT
1274 XFreeFont(Metadpy->dpy, ikfnt->info);
1281 #endif /* IGNORE_UNUSED_FUNCTIONS */
1285 * Prepare a new 'infofnt'
1287 #ifdef USE_JP_FONTSTRUCT
1288 static errr Infofnt_prepare(XFontStruct *info, XFontStruct *kinfo)
1291 static errr Infofnt_prepare(XFontSet info)
1293 static errr Infofnt_prepare(XFontStruct *info)
1298 infofnt *ifnt = Infofnt;
1300 #ifdef USE_JP_FONTSTRUCT
1301 infofnt *ikfnt = Infokfnt;
1305 XFontStruct **fontinfo;
1308 int ascent, descent, width;
1311 /* Assign the struct */
1315 n_fonts = XFontsOfFontSet(info, &fontinfo, &fontname);
1317 ascent = descent = width = 0;
1318 while(n_fonts-- > 0){
1319 cs = &((*fontinfo)->max_bounds);
1320 if(ascent < (*fontinfo)->ascent) ascent = (*fontinfo)->ascent;
1321 if(descent < (*fontinfo)->descent) descent = (*fontinfo)->descent;
1322 if(((*fontinfo)->max_byte1) > 0){
1323 /* 多バイト文字の場合は幅半分(端数切り上げ)で評価する */
1324 if(width < (cs->width+1)/2) width = (cs->width+1)/2;
1326 if(width < cs->width) width = cs->width;
1332 ifnt->hgt = ascent + descent;
1335 /* Jump into the max bouonds thing */
1336 cs = &(info->max_bounds);
1338 /* Extract default sizing info */
1339 ifnt->asc = info->ascent;
1340 ifnt->hgt = info->ascent + info->descent;
1341 ifnt->wid = cs->width;
1345 ifnt->twid = 2 * ifnt->wid;
1347 ifnt->twid = ifnt->wid;
1349 #ifdef USE_JP_FONTSTRUCT
1350 /* Assign the struct */
1351 ikfnt->info = kinfo;
1353 /* Jump into the max bouonds thing */
1354 cs = &(kinfo->max_bounds);
1356 /* Extract default sizing info */
1357 ikfnt->asc = kinfo->ascent;
1358 ikfnt->hgt = kinfo->ascent + kinfo->descent;
1359 ikfnt->wid = cs->width;
1362 #ifdef OBSOLETE_SIZING_METHOD
1363 /* Extract default sizing info */
1364 ifnt->asc = cs->ascent;
1365 ifnt->hgt = (cs->ascent + cs->descent);
1366 ifnt->wid = cs->width;
1375 #ifndef IGNORE_UNUSED_FUNCTIONS
1378 * Initialize a new 'infofnt'.
1380 #ifdef USE_JP_FONTSTRUCT
1381 static errr Infofnt_init_real(XFontStruct *info, XFontStruct *kinfo)
1384 static errr Infofnt_init_real(XFontSet info)
1386 static errr Infofnt_init_real(XFontStruct *info)
1391 /* Wipe the thing */
1392 (void)WIPE(Infofnt, infofnt);
1394 #ifdef USE_JP_FONTSTRUCT
1395 WIPE(Infokfnt, infofnt);
1400 #ifdef USE_JP_FONTSTRUCT
1403 /* Attempt to prepare it */
1404 #ifdef USE_JP_FONTSTRUCT
1405 return (Infofnt_prepare (info, kinfo));
1407 return (Infofnt_prepare(info));
1412 #endif /* IGNORE_UNUSED_FUNCTIONS */
1416 * Init an infofnt by its Name
1419 * name: The name of the requested Font
1421 #ifdef USE_JP_FONTSTRUCT
1422 static void Infofnt_init_data(concptr name, concptr kname)
1424 static void Infofnt_init_data(concptr name)
1430 char **missing_list;
1438 #ifdef USE_JP_FONTSTRUCT
1441 /*** Load the info Fresh, using the name ***/
1443 /* If the name is not given, report an error */
1444 if (!name || !*name) quit("Missing font!");
1446 #ifdef USE_JP_FONTSTRUCT
1447 if (!kname || !*kname) quit("Missing kanji font!");
1449 /* Attempt to load the font */
1451 info = XCreateFontSet(Metadpy->dpy, name, &missing_list, &missing_count, &default_font);
1452 if(missing_count > 0){
1453 printf("missing font(s): \n");
1454 while(missing_count-- > 0){
1455 printf("\t%s\n", missing_list[missing_count]);
1457 XFreeStringList(missing_list);
1460 info = XLoadQueryFont(Metadpy->dpy, name);
1461 #ifdef USE_JP_FONTSTRUCT
1462 kinfo = XLoadQueryFont(Metadpy->dpy, kname);
1467 /* The load failed, try to recover */
1468 if (!info) quit_fmt("Failed to find font:\"%s\"", name);
1469 #ifdef USE_JP_FONTSTRUCT
1470 if (!kinfo) quit_fmt("Failed to find font:\"%s\"", kname);
1475 /*** Init the font ***/
1477 /* Wipe the thing */
1478 (void)WIPE(Infofnt, infofnt);
1480 #ifdef USE_JP_FONTSTRUCT
1481 WIPE(Infokfnt, infofnt);
1483 /* Attempt to prepare it */
1484 #ifdef USE_JP_FONTSTRUCT
1485 if (Infofnt_prepare(info, kinfo))
1487 if (Infofnt_prepare(info))
1493 XFreeFontSet(Metadpy->dpy, info);
1495 XFreeFont(Metadpy->dpy, info);
1496 #ifdef USE_JP_FONTSTRUCT
1497 XFreeFont(Metadpy->dpy, kinfo);
1501 quit_fmt("Failed to prepare font:\"%s\"", name);
1504 /* Save a copy of the font name */
1505 Infofnt->name = string_make(name);
1506 #ifdef USE_JP_FONTSTRUCT
1507 Infokfnt->name = string_make(kname);
1510 /* Mark it as nukable */
1512 #ifdef USE_JP_FONTSTRUCT
1518 #ifdef USE_JP_FONTSTRUCT
1520 * EUC日本語コードを含む文字列を表示する (Xlib)
1523 XDrawMultiString(display,d,gc, x, y, string, len, afont,
1524 afont_width, afont_height, afont_ascent, kfont, kfont_width)
1532 int afont_width, afont_height, afont_ascent;
1539 unsigned char *endp;
1542 endp = string + len;
1544 while ( str < endp && *str ) {
1547 if ( (*str) == 0x7f ) {
1551 /* 連続する0x7Fの長さを検出 */
1553 while ( str < endp && (*str) == 0x7f ) {
1559 XFillRectangle( display, d, gc, x, y-afont_ascent,
1560 slen * afont_width, afont_height);
1563 x += afont_width * slen;
1567 if ( iskanji(*str) ) {
1571 /* 連続するUJIS文字の長さを検出 */
1573 while ( str < endp && *str && iskanji(*str) ) {
1574 kanji[slen].byte1 = *str++ & 0x7f;
1575 kanji[slen++].byte2 = *str++ & 0x7f;
1579 XSetFont( display, gc, kfont->fid );
1580 XDrawImageString16( display, d, gc, x, y, kanji, slen );
1584 x += kfont_width * slen;
1588 /* 非漢字(=ASCIIと仮定)の始まり */
1590 /* 連続するASCII文字を検出 */
1593 while ( str < endp && *str && !iskanji(*str) ) {
1595 if (*str == 0x7f)break;
1602 XSetFont( display, gc, afont->fid );
1603 XDrawImageString( display, d, gc, x, y, p, slen );
1606 x += afont_width * slen;
1615 static errr Infofnt_text_std(int x, int y, concptr str, int len)
1620 /*** Do a brief info analysis ***/
1622 /* Do nothing if the string is null */
1623 if (!str || !*str) return (-1);
1625 /* Get the length of the string */
1626 if (len < 0) len = strlen(str);
1628 /*** Decide where to place the string, vertically ***/
1630 /* Ignore Vertical Justifications */
1631 y = (y * Infofnt->hgt) + Infofnt->asc + Infowin->oy;
1634 /*** Decide where to place the string, horizontally ***/
1636 /* Line up with x at left edge of column 'x' */
1637 x = (x * Infofnt->wid) + Infowin->ox;
1640 /*** Actually draw 'str' onto the infowin ***/
1643 /* Be sure the correct font is ready */
1644 XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1647 /*** Handle the fake mono we can enforce on fonts ***/
1649 /* Monotize the font */
1652 #ifdef USE_JP_FONTSTRUCT
1653 /* Be sure the correct font is ready */
1654 XSetFont(Metadpy->dpy, Infoclr->gc, Infofnt->info->fid);
1656 /* Do each character */
1657 for (i = 0; i < len; ++i)
1659 /* Note that the Infoclr is set up to contain the Infofnt */
1660 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1661 x + i * Infofnt->wid + Infofnt->off, y, str + i, 1);
1665 /* Assume monoospaced font */
1668 /* Note that the Infoclr is set up to contain the Infofnt */
1669 #ifdef USE_JP_FONTSTRUCT
1670 /* 漢字フォントの表示幅は ASCIIフォントの2倍に固定 */
1671 XDrawMultiString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1673 Infofnt->info, Infofnt->wid, Infofnt->hgt,
1675 Infokfnt->info, Infofnt->wid * 2);
1679 iconv_t cd = iconv_open("UTF-8", "EUC-JP");
1681 size_t outlen = len * 2;
1682 char *kanji = malloc(outlen);
1683 char *sp; char *kp = kanji;
1685 my_strcpy(sbuf, str, sizeof(sbuf));
1687 iconv(cd, &sp, &inlen, &kp, &outlen);
1690 XmbDrawImageString(Metadpy->dpy, Infowin->win, Infofnt->info,
1691 Infoclr->gc, x, y, kanji, kp-kanji);
1694 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1708 * Painting where text would be
1710 static errr Infofnt_text_non(int x, int y, concptr str, int len)
1715 /*** Find the width ***/
1717 /* Negative length is a flag to count the characters in str */
1718 if (len < 0) len = strlen(str);
1720 /* The total width will be 'len' chars * standard width */
1721 w = len * Infofnt->wid;
1724 /*** Find the X dimensions ***/
1726 /* Line up with x at left edge of column 'x' */
1727 x = x * Infofnt->wid + Infowin->ox;
1730 /*** Find other dimensions ***/
1732 /* Simply do 'Infofnt->hgt' (a single row) high */
1735 /* Simply do "at top" in row 'y' */
1736 y = y * h + Infowin->oy;
1739 /*** Actually 'paint' the area ***/
1741 /* Just do a Fill Rectangle */
1742 XFillRectangle(Metadpy->dpy, Infowin->win, Infoclr->gc, x, y, w, h);
1750 /*************************************************************************/
1754 * Angband specific code follows... (ANGBAND)
1759 * Hack -- cursor color
1761 static infoclr *xor;
1764 * Actual color table
1766 static infoclr *clr[256];
1769 * Color info (unused, red, green, blue).
1771 static byte color_table[256][4];
1776 typedef struct term_data term_data;
1779 * A structure for each "term"
1786 #ifdef USE_JP_FONTSTRUCT
1797 /* Tempory storage for overlaying tiles. */
1806 * The number of term data structures
1808 #define MAX_TERM_DATA 8
1811 * The array of term data structures
1813 static term_data data[MAX_TERM_DATA];
1816 /* Use short names for the most commonly used elements of various structures. */
1817 #define DPY (Metadpy->dpy)
1818 #define WIN (Infowin->win)
1821 /* Describe a set of co-ordinates. */
1822 typedef struct co_ord co_ord;
1831 * A special structure to store information about the text currently
1834 typedef struct x11_selection_type x11_selection_type;
1835 struct x11_selection_type
1837 bool select; /* The selection is currently in use. */
1838 bool drawn; /* The selection is currently displayed. */
1839 term *t; /* The window where the selection is found. */
1840 co_ord init; /* The starting co-ordinates. */
1841 co_ord cur; /* The end co-ordinates (the current ones if still copying). */
1842 co_ord old; /* The previous end co-ordinates. */
1843 Time time; /* The time at which the selection was finalised. */
1846 static x11_selection_type s_ptr[1];
1850 * Process a keypress event
1852 * Also appears in "main-xaw.c".
1854 static void react_keypress(XKeyEvent *xev)
1856 int i, n, mc, ms, mo, mx;
1860 XKeyEvent *ev = (XKeyEvent*)(xev);
1868 int valid_keysym = TRUE;
1871 /* Check for "normal" keypresses */
1873 if(Focuswin && Focuswin->xic){
1875 n = XmbLookupString(Focuswin->xic, ev, buf, 125, &ks, &status);
1876 if(status == XBufferOverflow){
1877 printf("Input is too long, and dropped\n");
1880 if(status != XLookupKeySym && status != XLookupBoth){
1881 valid_keysym = FALSE;
1884 n = XLookupString(ev, buf, 125, &ks, NULL);
1887 n = XLookupString(ev, buf, 125, &ks, NULL);
1895 /* Enqueue the normal key(s) */
1896 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1903 /* Hack -- Ignore "modifier keys" */
1904 if (IsModifierKey(ks)) return;
1907 /* Hack -- convert into an unsigned int */
1910 /* Extract four "modifier flags" */
1911 mc = (ev->state & ControlMask) ? TRUE : FALSE;
1912 ms = (ev->state & ShiftMask) ? TRUE : FALSE;
1913 mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
1914 mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
1917 /* Normal keys with no modifiers */
1918 if (n && !mo && !mx && !IsSpecialKey(ks))
1920 /* Enqueue the normal key(s) */
1921 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
1928 /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1933 Term_keypress(ESCAPE);
1939 Term_keypress('\r');
1945 Term_keypress('\t');
1951 Term_keypress(0x7f);
1956 Term_keypress('\010');
1962 /* Hack -- Use the KeySym */
1965 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
1966 mc ? "N" : "", ms ? "S" : "",
1967 mo ? "O" : "", mx ? "M" : "",
1968 (unsigned long)(ks), 13);
1971 /* Hack -- Use the Keycode */
1974 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
1975 mc ? "N" : "", ms ? "S" : "",
1976 mo ? "O" : "", mx ? "M" : "",
1980 /* Enqueue the "macro trigger" string */
1981 for (i = 0; msg[i]; i++) Term_keypress(msg[i]);
1984 /* Hack -- auto-define macros as needed */
1985 if (n && (macro_find_exact(msg) < 0))
1987 /* Create a macro */
1988 macro_add(msg, buf);
1994 * Find the square a particular pixel is part of.
1996 static void pixel_to_square(int * const x, int * const y,
1997 const int ox, const int oy)
1999 (*x) = (ox - Infowin->ox) / Infofnt->wid;
2000 (*y) = (oy - Infowin->oy) / Infofnt->hgt;
2004 * Find the pixel at the top-left corner of a square.
2006 static void square_to_pixel(int * const x, int * const y,
2007 const int ox, const int oy)
2009 (*x) = ox * Infofnt->wid + Infowin->ox;
2010 (*y) = oy * Infofnt->hgt + Infowin->oy;
2014 * Convert co-ordinates from starting corner/opposite corner to minimum/maximum.
2016 static void sort_co_ord(co_ord *min, co_ord *max,
2017 const co_ord *b, const co_ord *a)
2019 min->x = MIN(a->x, b->x);
2020 min->y = MIN(a->y, b->y);
2021 max->x = MAX(a->x, b->x);
2022 max->y = MAX(a->y, b->y);
2026 * Remove the selection by redrawing it.
2028 static void mark_selection_clear(int x1, int y1, int x2, int y2)
2030 Term_redraw_section(x1,y1,x2,y2);
2034 * Select an area by drawing a grey box around it.
2035 * NB. These two functions can cause flicker as the selection is modified,
2036 * as the game redraws the entire marked section.
2038 static void mark_selection_mark(int x1, int y1, int x2, int y2)
2040 square_to_pixel(&x1, &y1, x1, y1);
2041 square_to_pixel(&x2, &y2, x2, y2);
2042 XDrawRectangle(Metadpy->dpy, Infowin->win, clr[2]->gc, x1, y1,
2043 x2-x1+Infofnt->wid - 1, y2-y1+Infofnt->hgt - 1);
2047 * Mark a selection by drawing boxes around it (for now).
2049 static void mark_selection(void)
2053 bool draw = s_ptr->select;
2054 bool clear = s_ptr->drawn;
2056 /* Open the correct term if necessary. */
2057 if (s_ptr->t != old) Term_activate(s_ptr->t);
2061 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->old);
2062 mark_selection_clear(min.x, min.y, max.x, max.y);
2066 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2067 mark_selection_mark(min.x, min.y, max.x, max.y);
2070 /* Finish on the current term. */
2071 if (s_ptr->t != old) Term_activate(old);
2073 s_ptr->old.x = s_ptr->cur.x;
2074 s_ptr->old.y = s_ptr->cur.y;
2075 s_ptr->drawn = s_ptr->select;
2079 * Forget a selection for one reason or another.
2081 static void copy_x11_release(void)
2083 /* Deselect the current selection. */
2084 s_ptr->select = FALSE;
2086 /* Remove its graphical represesntation. */
2091 * Start to select some text on the screen.
2093 static void copy_x11_start(int x, int y)
2095 if (s_ptr->select) copy_x11_release();
2097 /* Remember where the selection started. */
2099 s_ptr->init.x = s_ptr->cur.x = s_ptr->old.x = x;
2100 s_ptr->init.y = s_ptr->cur.y = s_ptr->old.y = y;
2104 * Respond to movement of the mouse when selecting text.
2106 static void copy_x11_cont(int x, int y, unsigned int buttons)
2108 /* Use the nearest square within bounds if the mouse is outside. */
2109 x = MIN(MAX(x, 0), Term->wid-1);
2110 y = MIN(MAX(y, 0), Term->hgt-1);
2112 /* The left mouse button isn't pressed. */
2113 if (~buttons & Button1Mask) return;
2115 /* Not a selection in this window. */
2116 if (s_ptr->t != Term) return;
2118 /* Not enough movement. */
2119 if (x == s_ptr->old.x && y == s_ptr->old.y && s_ptr->select) return;
2121 /* Something is being selected. */
2122 s_ptr->select = TRUE;
2124 /* Track the selection. */
2128 /* Hack - display it inefficiently. */
2133 * Respond to release of the left mouse button by putting the selected text in
2134 * the primary buffer.
2136 static void copy_x11_end(const Time time)
2139 if (!s_ptr->select) return;
2141 /* Not a selection in this window. */
2142 if (s_ptr->t != Term) return;
2144 /* Remember when the selection was finalised. */
2147 /* Acquire the primary selection. */
2148 XSetSelectionOwner(Metadpy->dpy, XA_PRIMARY, Infowin->win, time);
2149 if (XGetSelectionOwner(Metadpy->dpy, XA_PRIMARY) != Infowin->win)
2151 /* Failed to acquire the selection, so forget it. */
2152 /* bell("Failed to acquire primary buffer."); */
2153 s_ptr->select = FALSE;
2159 static Atom xa_targets, xa_timestamp, xa_text, xa_compound_text;
2162 * Set the required variable atoms at start-up to avoid errors later.
2164 static void set_atoms(void)
2166 xa_targets = XInternAtom(DPY, "TARGETS", False);
2167 xa_timestamp = XInternAtom(DPY, "TIMESTAMP", False);
2168 xa_text = XInternAtom(DPY, "TEXT", False);
2169 xa_compound_text = XInternAtom(DPY, "COMPOUND_TEXT", False);
2173 static Atom request_target = 0;
2176 * Send a message to request that the PRIMARY buffer be sent here.
2178 static void paste_x11_request(Atom target, const Time time)
2181 * It's from some sample programs on the web.
2182 * What does it mean? -- XXX
2184 Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2186 /* Check the owner. */
2187 if (XGetSelectionOwner(DPY, XA_PRIMARY) == None)
2190 /* bell("No selection found."); */
2194 request_target = target;
2196 /* Request the event */
2197 XConvertSelection(DPY, XA_PRIMARY, target, property, WIN, time);
2202 * Add the contents of the PRIMARY buffer to the input queue.
2204 * Hack - This doesn't use the "time" of the event, and so accepts anything a
2205 * client tries to send it.
2207 static void paste_x11_accept(const XSelectionEvent *ptr)
2210 const long offset = 0;
2211 const long length = 32000;
2212 XTextProperty xtextproperty;
2216 * It's from some sample programs on the web.
2217 * What does it mean? -- XXX
2219 Atom property = XInternAtom(DPY, "__COPY_TEXT", False);
2223 if (ptr->property == None)
2225 if (request_target == xa_compound_text)
2227 /* Re-request as STRING */
2228 paste_x11_request(XA_STRING, ptr->time);
2233 plog("Paste failure (remote client could not send).");
2238 if (ptr->selection != XA_PRIMARY)
2240 plog("Paste failure (remote client did not send primary selection).");
2244 if (ptr->target != request_target)
2246 plog("Paste failure (selection in unknown format).");
2251 if (XGetWindowProperty(Metadpy->dpy, Infowin->win, property, offset,
2252 length, TRUE, request_target,
2253 &xtextproperty.encoding,
2254 &xtextproperty.format,
2255 &xtextproperty.nitems,
2257 &xtextproperty.value)
2264 if (request_target == xa_compound_text)
2269 XmbTextPropertyToTextList(DPY, &xtextproperty, &list, &count);
2275 for (i = 0; i < count; i++)
2277 /* Paste the text. */
2278 err = type_string(list[i], 0);
2283 /* Free the string */
2284 XFreeStringList(list);
2287 else /* if (request_target == XA_STRING) */
2289 /* Paste the text. */
2290 err = type_string((char *)xtextproperty.value, xtextproperty.nitems);
2293 /* Free the data pasted. */
2294 XFree(xtextproperty.value);
2299 plog("Paste failure (too much text selected).");
2305 * Add a character to a string in preparation for sending it to another
2306 * client as a STRING.
2307 * This doesn't change anything, as clients tend not to have difficulty in
2308 * receiving this format (although the standard specifies a restricted set).
2309 * Strings do not have a colour.
2311 static bool paste_x11_send_text(XSelectionRequestEvent *rq)
2321 /* Too old, or incorrect call. */
2322 if (rq->time < s_ptr->time) return FALSE;
2324 /* Work out which way around to paste. */
2325 sort_co_ord(&min, &max, &s_ptr->init, &s_ptr->cur);
2328 if (XGetSelectionOwner(DPY, XA_PRIMARY) != WIN)
2330 /* bell("Someone stole my selection!"); */
2334 /* Delete the old value of the property. */
2335 XDeleteProperty(DPY, rq->requestor, rq->property);
2337 for (n = 0, y = 0; y < Term->hgt; y++)
2342 if (y < min.y) continue;
2343 if (y > max.y) break;
2345 for (l = 0, x = 0; x < Term->wid; x++)
2348 if (x > max.x) break;
2350 /* Find the character. */
2351 Term_what(x, y, &a, &c);
2353 if (1 == kanji) kanji = 2;
2354 else if (iskanji(c)) kanji = 1;
2357 if (x < min.x) continue;
2360 * A single kanji character was divided in two...
2361 * Delete the garbage.
2363 if ((2 == kanji && x == min.x) ||
2364 (1 == kanji && x == max.x))
2367 if (x > max.x) break;
2368 if (x < min.x) continue;
2370 /* Find the character. */
2371 Term_what(x, y, &a, &c);
2379 /* Ignore trailing spaces */
2380 while (buf[l-1] == ' ') l--;
2382 /* Terminate all line unless it's single line. */
2392 list[n++] = (char *)string_make(buf);
2395 /* End of the list */
2399 if (rq->target == XA_STRING)
2401 for (n = 0; list[n]; n++)
2403 /* Send the (non-empty) string. */
2404 XChangeProperty(DPY, rq->requestor, rq->property, rq->target, 8,
2405 PropModeAppend, (unsigned char *)list[n], strlen(list[n]));
2409 else if (rq->target == xa_text ||
2410 rq->target == xa_compound_text)
2412 XTextProperty text_prop;
2413 XICCEncodingStyle style;
2415 if (rq->target == xa_text)
2416 style = XStdICCTextStyle;
2417 else /* if (rq->target == xa_compound_text) */
2418 style = XCompoundTextStyle;
2421 XmbTextListToTextProperty(DPY, list, n, style, &text_prop))
2423 /* Send the compound text */
2424 XChangeProperty(DPY,
2433 /* Free the data. */
2434 XFree(text_prop.value);
2438 /* Free the list of strings */
2439 for (n = 0; list[n]; n++)
2441 string_free(list[n]);
2448 * Send some text requested by another X client.
2450 static void paste_x11_send(XSelectionRequestEvent *rq)
2453 XSelectionEvent *ptr = &(event.xselection);
2455 /* Set the event parameters. */
2456 ptr->type = SelectionNotify;
2457 ptr->property = rq->property;
2458 ptr->display = rq->display;
2459 ptr->requestor = rq->requestor;
2460 ptr->selection = rq->selection;
2461 ptr->target = rq->target;
2462 ptr->time = rq->time;
2464 /* Paste the appropriate information for each target type.
2465 * Note that this currently rejects MULTIPLE targets.
2468 if (rq->target == XA_STRING ||
2469 rq->target == xa_text ||
2470 rq->target == xa_compound_text)
2472 if (!paste_x11_send_text(rq))
2473 ptr->property = None;
2475 else if (rq->target == xa_targets)
2477 Atom target_list[4];
2478 target_list[0] = XA_STRING;
2479 target_list[1] = xa_text;
2480 target_list[2] = xa_compound_text;
2481 target_list[3] = xa_targets;
2482 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2483 (8 * sizeof(target_list[0])), PropModeReplace,
2484 (unsigned char *)target_list,
2485 (sizeof(target_list) / sizeof(target_list[0])));
2487 else if (rq->target == xa_timestamp)
2489 XChangeProperty(DPY, rq->requestor, rq->property, rq->target,
2490 (8 * sizeof(Time)), PropModeReplace,
2491 (unsigned char *)s_ptr->time, 1);
2495 ptr->property = None;
2498 /* Send whatever event we're left with. */
2499 XSendEvent(DPY, rq->requestor, FALSE, NoEventMask, &event);
2504 * Handle various events conditional on presses of a mouse button.
2506 static void handle_button(Time time, int x, int y, int button,
2509 /* The co-ordinates are only used in Angband format. */
2510 pixel_to_square(&x, &y, x, y);
2512 if (press && button == 1) copy_x11_start(x, y);
2513 if (!press && button == 1) copy_x11_end(time);
2514 if (!press && button == 2) paste_x11_request(xa_compound_text, time);
2521 static errr CheckEvent(bool wait)
2523 term_data *old_td = (term_data*)(Term->data);
2525 XEvent xev_body, *xev = &xev_body;
2527 term_data *td = NULL;
2528 infowin *iwin = NULL;
2536 /* Do not wait unless requested */
2537 if (!wait && !XPending(Metadpy->dpy)) return (1);
2540 * Hack - redraw the selection, if needed.
2541 * This doesn't actually check that one of its squares was drawn to,
2542 * only that this may have happened.
2544 if (s_ptr->select && !s_ptr->drawn) mark_selection();
2546 /* Load the Event */
2547 XNextEvent(Metadpy->dpy, xev);
2550 /* #define DEBUG_EVENT */
2553 printf("event: type=%d", xev->type);
2556 printf("(KeyPress), keycode=%X", xev->xkey.keycode);
2559 printf("(FocusIn)");
2562 printf("(FocusOut)");
2564 case ReparentNotify:
2565 printf("(ReparentNotify)");
2567 case ConfigureNotify:
2568 printf("(ConfigureNotify)");
2571 printf("(MapNotify)");
2577 printf("(ClientMessage)");
2583 if (XFilterEvent(xev, xev->xany.window)
2584 /*XFilterEvent(xev, (data[0].win)->win)*/){
2586 printf(", [filtered by IM]\n");
2588 goto redo_checkevent;
2595 /* Notice new keymaps */
2596 if (xev->type == MappingNotify)
2598 XRefreshKeyboardMapping(&xev->xmapping);
2603 /* Scan the windows */
2604 for (i = 0; i < MAX_TERM_DATA; i++)
2606 if (!data[i].win) continue;
2607 if (xev->xany.window == data[i].win->win)
2615 /* Unknown window */
2616 if (!td || !iwin) return (0);
2619 /* Hack -- activate the Term */
2620 Term_activate(&td->t);
2622 /* Hack -- activate the window */
2626 /* Switch on the Type */
2632 bool press = (xev->type == ButtonPress);
2634 /* Where is the mouse */
2635 int x = xev->xbutton.x;
2636 int y = xev->xbutton.y;
2640 /* Which button is involved */
2641 if (xev->xbutton.button == Button1) z = 1;
2642 else if (xev->xbutton.button == Button2) z = 2;
2643 else if (xev->xbutton.button == Button3) z = 3;
2644 else if (xev->xbutton.button == Button4) z = 4;
2645 else if (xev->xbutton.button == Button5) z = 5;
2649 handle_button(xev->xbutton.time, x, y, z, press);
2664 /* Where is the mouse */
2665 int x = xev->xmotion.x;
2666 int y = xev->xmotion.y;
2667 unsigned int z = xev->xmotion.state;
2669 /* Convert to co-ordinates Angband understands. */
2670 pixel_to_square(&x, &y, x, y);
2672 /* Highlight the current square, if appropriate. */
2673 /* highlight_square(window, y, x); */
2675 /* Alter the selection if appropriate. */
2676 copy_x11_cont(x, y, z);
2683 case SelectionNotify:
2685 paste_x11_accept(&(xev->xselection));
2689 case SelectionRequest:
2691 paste_x11_send(&(xev->xselectionrequest));
2695 case SelectionClear:
2697 s_ptr->select = FALSE;
2710 /* Hack -- use "old" term */
2711 Term_activate(&old_td->t);
2713 /* Process the key */
2714 react_keypress(&(xev->xkey));
2723 /* Ignore "extra" exposes */
2724 /*if (xev->xexpose.count) break;*/
2726 /* Clear the window */
2729 x1 = (xev->xexpose.x - Infowin->ox)/Infofnt->wid;
2730 x2 = (xev->xexpose.x + xev->xexpose.width -
2731 Infowin->ox)/Infofnt->wid;
2733 y1 = (xev->xexpose.y - Infowin->oy)/Infofnt->hgt;
2734 y2 = (xev->xexpose.y + xev->xexpose.height -
2735 Infowin->oy)/Infofnt->hgt;
2737 Term_redraw_section(x1, y1, x2, y2);
2747 Infowin->mapped = 1;
2748 Term->mapped_flag = TRUE;
2754 Infowin->mapped = 0;
2755 Term->mapped_flag = FALSE;
2759 /* Move and/or Resize */
2760 case ConfigureNotify:
2762 int cols, rows, wid, hgt;
2764 int ox = Infowin->ox;
2765 int oy = Infowin->oy;
2767 /* Save the new Window Parms */
2768 Infowin->x = xev->xconfigure.x;
2769 Infowin->y = xev->xconfigure.y;
2770 Infowin->w = xev->xconfigure.width;
2771 Infowin->h = xev->xconfigure.height;
2773 /* Determine "proper" number of rows/cols */
2774 cols = ((Infowin->w - (ox + ox)) / td->fnt->wid);
2775 rows = ((Infowin->h - (oy + oy)) / td->fnt->hgt);
2777 /* Hack -- minimal size */
2778 if (cols < 1) cols = 1;
2779 if (rows < 1) rows = 1;
2783 /* Hack the main window must be at least 80x24 */
2784 if (cols < 80) cols = 80;
2785 if (rows < 24) rows = 24;
2788 /* Desired size of window */
2789 wid = cols * td->fnt->wid + (ox + ox);
2790 hgt = rows * td->fnt->hgt + (oy + oy);
2792 /* Resize the Term (if needed) */
2793 Term_resize(cols, rows);
2795 /* Resize the windows if any "change" is needed */
2796 if ((Infowin->w != wid) || (Infowin->h != hgt))
2799 Infowin_set(td->win);
2800 Infowin_resize(wid, hgt);
2809 XSetICFocus(iwin->xic);
2817 XUnsetICFocus(iwin->xic);
2819 /* Focuswin = NULL;*/
2826 /* Hack -- Activate the old term */
2827 Term_activate(&old_td->t);
2829 /* Hack -- Activate the proper window */
2830 Infowin_set(old_td->win);
2841 * Standard sound names
2843 static const concptr angband_sound_name[SOUND_MAX] =
2915 * An array of sound file names
2917 static concptr sound_file[SOUND_MAX];
2920 * Check for existance of a file
2922 static bool check_file(concptr s)
2926 fff = fopen(s, "r");
2927 if (!fff) return (FALSE);
2936 static void init_sound(void)
2941 char dir_xtra_sound[1024];
2943 /* Build the "sound" path */
2944 path_build(dir_xtra_sound, sizeof(dir_xtra_sound), ANGBAND_DIR_XTRA, "sound");
2946 /* Prepare the sounds */
2947 for (i = 1; i < SOUND_MAX; i++)
2949 /* Extract name of sound file */
2950 sprintf(wav, "%s.wav", angband_sound_name[i]);
2952 /* Access the sound */
2953 path_build(buf, sizeof(buf), dir_xtra_sound, wav);
2955 /* Save the sound filename, if it exists */
2956 if (check_file(buf)) sound_file[i] = string_make(buf);
2963 * Hack -- make a sound
2965 static errr Term_xtra_x11_sound(int v)
2969 /* Sound disabled */
2970 if (!use_sound) return (1);
2973 if ((v < 0) || (v >= SOUND_MAX)) return (1);
2976 if (!sound_file[v]) return (1);
2978 sprintf(buf,"./playwave.sh %s\n", sound_file[v]);
2980 return (system(buf) < 0);
2983 #endif /* USE_SOUND */
2987 * Handle "activation" of a term
2989 static errr Term_xtra_x11_level(int v)
2991 term_data *td = (term_data*)(Term->data);
2993 /* Handle "activate" */
2996 /* Activate the window */
2997 Infowin_set(td->win);
2999 /* Activate the font */
3000 Infofnt_set(td->fnt);
3001 #ifdef USE_JP_FONTSTRUCT
3002 Infokfnt_set(td->kfnt);
3014 static errr Term_xtra_x11_react(void)
3020 /* Check the colors */
3021 for (i = 0; i < 256; i++)
3023 if ((color_table[i][0] != angband_color_table[i][0]) ||
3024 (color_table[i][1] != angband_color_table[i][1]) ||
3025 (color_table[i][2] != angband_color_table[i][2]) ||
3026 (color_table[i][3] != angband_color_table[i][3]))
3030 /* Save new values */
3031 color_table[i][0] = angband_color_table[i][0];
3032 color_table[i][1] = angband_color_table[i][1];
3033 color_table[i][2] = angband_color_table[i][2];
3034 color_table[i][3] = angband_color_table[i][3];
3037 pixel = create_pixel(Metadpy->dpy,
3042 /* Change the foreground */
3043 Infoclr_set(clr[i]);
3044 Infoclr_change_fg(pixel);
3055 * Handle a "special request"
3057 static errr Term_xtra_x11(int n, int v)
3059 /* Handle a subset of the legal requests */
3063 case TERM_XTRA_NOISE: Metadpy_do_beep(); return (0);
3066 /* Make a special sound */
3067 case TERM_XTRA_SOUND: return (Term_xtra_x11_sound(v));
3070 /* Flush the output XXX XXX */
3071 case TERM_XTRA_FRESH: Metadpy_update(1, 0, 0); return (0);
3073 /* Process random events XXX */
3074 case TERM_XTRA_BORED: return (CheckEvent(0));
3076 /* Process Events XXX */
3077 case TERM_XTRA_EVENT: return (CheckEvent(v));
3079 /* Flush the events XXX */
3080 case TERM_XTRA_FLUSH: while (!CheckEvent(FALSE)); return (0);
3082 /* Handle change in the "level" */
3083 case TERM_XTRA_LEVEL: return (Term_xtra_x11_level(v));
3085 /* Clear the screen */
3086 case TERM_XTRA_CLEAR: Infowin_wipe(); s_ptr->drawn = FALSE; return (0);
3088 /* Delay for some milliseconds */
3089 case TERM_XTRA_DELAY: usleep(1000 * v); return (0);
3091 /* React to changes */
3092 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
3101 * Draw the cursor as an inverted rectangle.
3103 * Consider a rectangular outline like "main-mac.c". XXX XXX
3105 static errr Term_curs_x11(int x, int y)
3109 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3110 x * Infofnt->wid + Infowin->ox,
3111 y * Infofnt->hgt + Infowin->oy,
3112 Infofnt->wid - 1, Infofnt->hgt - 1);
3113 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3114 x * Infofnt->wid + Infowin->ox + 1,
3115 y * Infofnt->hgt + Infowin->oy + 1,
3116 Infofnt->wid - 3, Infofnt->hgt - 3);
3120 /* Draw the cursor */
3123 /* Hilite the cursor character */
3124 Infofnt_text_non(x, y, " ", 1);
3133 * Draw the double width cursor
3135 static errr Term_bigcurs_x11(int x, int y)
3139 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3140 x * Infofnt->wid + Infowin->ox,
3141 y * Infofnt->hgt + Infowin->oy,
3142 Infofnt->twid - 1, Infofnt->hgt - 1);
3143 XDrawRectangle(Metadpy->dpy, Infowin->win, xor->gc,
3144 x * Infofnt->wid + Infowin->ox + 1,
3145 y * Infofnt->hgt + Infowin->oy + 1,
3146 Infofnt->twid - 3, Infofnt->hgt - 3);
3150 /* Draw the cursor */
3153 /* Hilite the cursor character */
3154 Infofnt_text_non(x, y, " ", 2);
3162 * Erase some characters.
3164 static errr Term_wipe_x11(int x, int y, int n)
3166 /* Erase (use black) */
3167 Infoclr_set(clr[TERM_DARK]);
3169 /* Mega-Hack -- Erase some space */
3170 Infofnt_text_non(x, y, "", n);
3172 /* Redraw the selection if any, as it may have been obscured. (later) */
3173 s_ptr->drawn = FALSE;
3181 * Draw some textual characters.
3183 static errr Term_text_x11(TERM_LEN x, TERM_LEN y, int n, TERM_COLOR a, concptr s)
3186 Infoclr_set(clr[a]);
3189 Infofnt_text_std(x, y, s, n);
3191 /* Redraw the selection if any, as it may have been obscured. (later) */
3192 s_ptr->drawn = FALSE;
3202 * Draw some graphical characters.
3204 static errr Term_pict_x11(TERM_LEN x, TERM_LEN y, int n, const TERM_COLOR *ap, const char *cp, const TERM_COLOR *tap, const char *tcp)
3217 unsigned long pixel, blank;
3219 term_data *td = (term_data*)(Term->data);
3224 /* Add in affect of window boundaries */
3228 for (i = 0; i < n; ++i, x += td->fnt->wid)
3233 /* For extra speed - cache these values */
3234 x1 = (c&0x7F) * td->fnt->twid;
3235 y1 = (a&0x7F) * td->fnt->hgt;
3237 /* Illegal tile index */
3238 if (td->tiles->width < x1 + td->fnt->wid ||
3239 td->tiles->height < y1 + td->fnt->hgt)
3241 /* Draw black square */
3242 XFillRectangle(Metadpy->dpy, td->win->win, clr[0]->gc,
3244 td->fnt->twid, td->fnt->hgt);
3246 /* Skip drawing tile */
3253 /* For extra speed - cache these values */
3254 x2 = (tc&0x7F) * td->fnt->twid;
3255 y2 = (ta&0x7F) * td->fnt->hgt;
3257 /* Optimise the common case */
3258 if (((x1 == x2) && (y1 == y2)) ||
3259 !(((byte)ta & 0x80) && ((byte)tc & 0x80)) ||
3260 td->tiles->width < x2 + td->fnt->wid ||
3261 td->tiles->height < y2 + td->fnt->hgt)
3263 /* Draw object / terrain */
3264 XPutImage(Metadpy->dpy, td->win->win,
3269 td->fnt->twid, td->fnt->hgt);
3274 /* Mega Hack^2 - assume the top left corner is "black" */
3275 blank = XGetPixel(td->tiles, 0, td->fnt->hgt * 6);
3277 for (k = 0; k < td->fnt->twid; k++)
3279 for (l = 0; l < td->fnt->hgt; l++)
3281 /* If mask set... */
3282 if ((pixel = XGetPixel(td->tiles, x1 + k, y1 + l)) == blank)
3284 /* Output from the terrain */
3285 pixel = XGetPixel(td->tiles, x2 + k, y2 + l);
3288 /* Store into the temp storage. */
3289 XPutPixel(td->TmpImage, k, l, pixel);
3294 /* Draw to screen */
3296 XPutImage(Metadpy->dpy, td->win->win,
3300 td->fnt->twid, td->fnt->hgt);
3304 /* Redraw the selection if any, as it may have been obscured. (later) */
3305 s_ptr->drawn = FALSE;
3311 #endif /* USE_GRAPHICS */
3314 static void IMDestroyCallback(XIM, XPointer, XPointer);
3317 IMInstantiateCallback(Display *display, XPointer unused1, XPointer unused2)
3320 XIMCallback ximcallback;
3321 XIMStyles *xim_styles = NULL;
3328 xim = XOpenIM(display, NULL, NULL, NULL);
3330 printf("can't open IM\n");
3334 /* initialize destroy callback */
3335 ximcallback.callback = IMDestroyCallback;
3336 ximcallback.client_data = NULL;
3337 XSetIMValues(xim, XNDestroyCallback, &ximcallback, NULL);
3339 /* set style (only "Root" is supported yet...) */
3340 XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
3341 for (i = 0; i < xim_styles->count_styles; i++){
3342 if(xim_styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) break;
3344 if(i >= xim_styles->count_styles){
3345 printf("Sorry, your IM does not support 'Root' preedit style...\n");
3353 for (i = 0; i < MAX_TERM_DATA; i++)
3355 infowin *iwin = data[i].win;
3356 if (!iwin) continue;
3357 iwin->xic = XCreateIC(xim, XNInputStyle, (XIMPreeditNothing | XIMStatusNothing), XNClientWindow, iwin->win, XNFocusWindow, iwin->win, NULL);
3359 printf("Can't create input context for Term%d\n", i);
3362 if(XGetICValues(iwin->xic, XNFilterEvents, &iwin->xic_mask, NULL) != NULL){
3363 /* printf("Can't get XNFilterEvents\n"); */
3364 iwin->xic_mask = 0L;
3366 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask | iwin->xic_mask);
3372 static void IMDestroyCallback(XIM xim, XPointer client_data, XPointer call_data)
3380 if (call_data == NULL){
3381 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3384 for(i = 0; i < MAX_TERM_DATA; i++)
3386 infowin *iwin = data[i].win;
3389 XSelectInput(Metadpy->dpy, iwin->win, iwin->mask);
3390 iwin->xic_mask = 0L;
3395 Metadpy->xim = NULL;
3400 * Initialize a term_data
3402 static errr term_data_init(term_data *td, int i)
3406 concptr name = angband_term_name[i];
3409 #ifdef USE_JP_FONTSTRUCT
3441 /* Window specific font name */
3442 sprintf(buf, "ANGBAND_X11_FONT_%d", i);
3444 /* Check environment for that font */
3447 /* Check environment for "base" font */
3448 if (!font) font = getenv("ANGBAND_X11_FONT");
3450 /* No environment variables, use default font */
3457 font = DEFAULT_X11_FONT_0;
3462 font = DEFAULT_X11_FONT_1;
3467 font = DEFAULT_X11_FONT_2;
3472 font = DEFAULT_X11_FONT_3;
3477 font = DEFAULT_X11_FONT_4;
3482 font = DEFAULT_X11_FONT_5;
3487 font = DEFAULT_X11_FONT_6;
3492 font = DEFAULT_X11_FONT_7;
3497 font = DEFAULT_X11_FONT;
3502 #ifdef USE_JP_FONTSTRUCT
3503 /* Window specific font name */
3504 sprintf(buf, "ANGBAND_X11_KFONT_%d", i);
3506 /* Check environment for that font */
3507 kfont = getenv(buf);
3509 /* Check environment for "base" font */
3510 if (!kfont) kfont = getenv("ANGBAND_X11_KFONT");
3512 /* No environment variables, use default font */
3519 kfont = DEFAULT_X11_KFONT_0;
3524 kfont = DEFAULT_X11_KFONT_1;
3529 kfont = DEFAULT_X11_KFONT_2;
3534 kfont = DEFAULT_X11_KFONT_3;
3539 kfont = DEFAULT_X11_KFONT_4;
3544 kfont = DEFAULT_X11_KFONT_5;
3549 kfont = DEFAULT_X11_KFONT_6;
3554 kfont = DEFAULT_X11_KFONT_7;
3559 kfont = DEFAULT_X11_KFONT;
3564 /* Window specific location (x) */
3565 sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
3567 x = (str != NULL) ? atoi(str) : -1;
3569 /* Window specific location (y) */
3570 sprintf(buf, "ANGBAND_X11_AT_Y_%d", i);
3572 y = (str != NULL) ? atoi(str) : -1;
3575 /* Window specific cols */
3576 sprintf(buf, "ANGBAND_X11_COLS_%d", i);
3578 val = (str != NULL) ? atoi(str) : -1;
3579 if (val > 0) cols = val;
3581 /* Window specific rows */
3582 sprintf(buf, "ANGBAND_X11_ROWS_%d", i);
3584 val = (str != NULL) ? atoi(str) : -1;
3585 if (val > 0) rows = val;
3587 /* Hack the main window must be at least 80x24 */
3590 if (cols < 80) cols = 80;
3591 if (rows < 24) rows = 24;
3594 /* Window specific inner border offset (ox) */
3595 sprintf(buf, "ANGBAND_X11_IBOX_%d", i);
3597 val = (str != NULL) ? atoi(str) : -1;
3598 if (val > 0) ox = val;
3600 /* Window specific inner border offset (oy) */
3601 sprintf(buf, "ANGBAND_X11_IBOY_%d", i);
3603 val = (str != NULL) ? atoi(str) : -1;
3604 if (val > 0) oy = val;
3607 /* Prepare the standard font */
3608 #ifdef USE_JP_FONTSTRUCT
3609 MAKE(td->fnt, infofnt);
3610 Infofnt_set(td->fnt);
3611 MAKE(td->kfnt, infofnt);
3612 Infokfnt_set(td->kfnt);
3613 Infofnt_init_data(font, kfont);
3615 MAKE(td->fnt, infofnt);
3616 Infofnt_set(td->fnt);
3617 Infofnt_init_data(font);
3621 /* Hack -- key buffer size */
3622 num = ((i == 0) ? 1024 : 16);
3624 /* Assume full size windows */
3625 wid = cols * td->fnt->wid + (ox + ox);
3626 hgt = rows * td->fnt->hgt + (oy + oy);
3628 /* Create a top-window */
3629 MAKE(td->win, infowin);
3630 Infowin_set(td->win);
3631 Infowin_init_top(x, y, wid, hgt, 0,
3632 Metadpy->fg, Metadpy->bg);
3634 /* Ask for certain events */
3635 #if defined(USE_XIM)
3636 Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask);
3638 Infowin_set_mask(ExposureMask | StructureNotifyMask | KeyPressMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask);
3641 /* Set the window name */
3642 Infowin_set_name(name);
3644 /* Save the inner border */
3648 /* Make Class Hints */
3649 ch = XAllocClassHint();
3651 if (ch == NULL) quit("XAllocClassHint failed");
3653 strcpy(res_name, name);
3654 res_name[0] = FORCELOWER(res_name[0]);
3655 ch->res_name = res_name;
3657 strcpy(res_class, "Angband");
3658 ch->res_class = res_class;
3660 XSetClassHint(Metadpy->dpy, Infowin->win, ch);
3662 /* Make Size Hints */
3663 sh = XAllocSizeHints();
3666 if (sh == NULL) quit("XAllocSizeHints failed");
3668 /* Main window has a differing minimum size */
3671 /* Main window min size is 80x24 */
3672 sh->flags = PMinSize | PMaxSize;
3673 sh->min_width = 80 * td->fnt->wid + (ox + ox);
3674 sh->min_height = 24 * td->fnt->hgt + (oy + oy);
3675 sh->max_width = 255 * td->fnt->wid + (ox + ox);
3676 sh->max_height = 255 * td->fnt->hgt + (oy + oy);
3679 /* Other windows can be shrunk to 1x1 */
3683 sh->flags = PMinSize | PMaxSize;
3684 sh->min_width = td->fnt->wid + (ox + ox);
3685 sh->min_height = td->fnt->hgt + (oy + oy);
3686 sh->max_width = 256 * td->fnt->wid + (ox + ox);
3687 sh->max_height = 256 * td->fnt->hgt + (oy + oy);
3690 /* Resize increment */
3691 sh->flags |= PResizeInc;
3692 sh->width_inc = td->fnt->wid;
3693 sh->height_inc = td->fnt->hgt;
3695 /* Base window size */
3696 sh->flags |= PBaseSize;
3697 sh->base_width = (ox + ox);
3698 sh->base_height = (oy + oy);
3700 /* Use the size hints */
3701 XSetWMNormalHints(Metadpy->dpy, Infowin->win, sh);
3703 /* Map the window */
3708 wh = XAllocWMHints();
3709 if(wh == NULL) quit("XAllocWMHints failed");
3710 wh->flags = InputHint;
3712 XSetWMHints(Metadpy->dpy, Infowin->win, wh);
3715 /* Move the window to requested location */
3716 if ((x >= 0) && (y >= 0)) Infowin_impell(x, y);
3719 /* Initialize the term */
3720 term_init(t, cols, rows, num);
3722 /* Use a "soft" cursor */
3723 t->soft_cursor = TRUE;
3725 /* Erase with "white space" */
3726 t->attr_blank = TERM_WHITE;
3727 t->char_blank = ' ';
3730 t->xtra_hook = Term_xtra_x11;
3731 t->curs_hook = Term_curs_x11;
3732 t->bigcurs_hook = Term_bigcurs_x11;
3733 t->wipe_hook = Term_wipe_x11;
3734 t->text_hook = Term_text_x11;
3739 /* Activate (important) */
3748 * Initialization function for an "X11" module to Angband
3750 errr init_x11(int argc, char *argv[])
3754 concptr dpy_name = "";
3760 char filename[1024];
3766 #endif /* USE_GRAPHICS */
3770 for (i = 1; i < argc; i++)
3772 if (prefix(argv[i], "-d"))
3774 dpy_name = &argv[i][2];
3779 if (prefix(argv[i], "-s"))
3781 smoothRescaling = FALSE;
3785 if (prefix(argv[i], "-a"))
3787 arg_graphics = GRAPHICS_ADAM_BOLT;
3791 if (prefix(argv[i], "-o"))
3793 arg_graphics = GRAPHICS_ORIGINAL;
3797 if (prefix(argv[i], "-b"))
3799 arg_bigtile = use_bigtile = TRUE;
3802 #endif /* USE_GRAPHICS */
3804 if (prefix(argv[i], "-n"))
3806 num_term = atoi(&argv[i][2]);
3807 if (num_term > MAX_TERM_DATA) num_term = MAX_TERM_DATA;
3808 else if (num_term < 1) num_term = 1;
3812 if (prefix(argv[i], "--"))
3818 plog_fmt("Ignoring option: %s", argv[i]);
3824 /* Get locale information from environment variables */
3825 setlocale(LC_ALL, "");
3827 #ifdef DEFAULT_LOCALE
3828 if(!strcmp(setlocale(LC_ALL, NULL), "C")){
3829 printf("try default locale \"%s\"\n", DEFAULT_LOCALE);
3830 setlocale(LC_ALL, DEFAULT_LOCALE);
3834 if(!strcmp(setlocale(LC_ALL, NULL), "C"))
3836 printf("WARNING: Locale is not supported. Non-english font may be displayed incorrectly.\n");
3839 if(!XSupportsLocale()){
3840 printf("can't support locale in X\n");
3841 setlocale(LC_ALL, "C");
3844 /* Set locale to "C" without using environment variables */
3845 setlocale(LC_ALL, "C");
3848 #endif /* USE_LOCALE */
3851 /* Init the Metadpy if possible */
3852 if (Metadpy_init_name(dpy_name)) return (-1);
3855 /* Prepare cursor color */
3858 Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
3861 /* Prepare normal colors */
3862 for (i = 0; i < 256; ++i)
3866 MAKE(clr[i], infoclr);
3868 Infoclr_set(clr[i]);
3870 /* Acquire Angband colors */
3871 color_table[i][0] = angband_color_table[i][0];
3872 color_table[i][1] = angband_color_table[i][1];
3873 color_table[i][2] = angband_color_table[i][2];
3874 color_table[i][3] = angband_color_table[i][3];
3876 /* Default to monochrome */
3877 pixel = ((i == 0) ? Metadpy->bg : Metadpy->fg);
3883 pixel = create_pixel(Metadpy->dpy,
3889 /* Initialize the color */
3890 Infoclr_init_ppn(pixel, Metadpy->bg, "cpy", 0);
3894 /* Prepare required atoms. */
3898 /* Initialize the windows */
3899 for (i = 0; i < num_term; i++)
3901 term_data *td = &data[i];
3903 /* Initialize the term_data */
3904 term_data_init(td, i);
3906 /* Save global entry */
3907 angband_term[i] = Term;
3910 /* Raise the "Angband" window */
3911 Infowin_set(data[0].win);
3914 /* Activate the "Angband" window screen */
3915 Term_activate(&data[0].t);
3920 p = XSetLocaleModifiers("");
3922 p = XSetLocaleModifiers("@im=");
3924 /* printf("XMODIFIERS=\"%s\"\n", p); */
3926 XRegisterIMInstantiateCallback(Metadpy->dpy, NULL, NULL, NULL, IMInstantiateCallback, NULL);
3930 /* initialize sound */
3931 if (arg_sound) init_sound();
3937 switch (arg_graphics)
3939 case GRAPHICS_ORIGINAL:
3940 /* Try the "8x8.bmp" file */
3941 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/8x8.bmp");
3943 /* Use the "8x8.bmp" file if it exists */
3944 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3947 use_graphics = TRUE;
3949 pict_wid = pict_hgt = 8;
3951 ANGBAND_GRAF = "old";
3956 case GRAPHICS_ADAM_BOLT:
3957 /* Try the "16x16.bmp" file */
3958 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, "graf/16x16.bmp");
3960 /* Use the "16x16.bmp" file if it exists */
3961 if (0 == fd_close(fd_open(filename, O_RDONLY)))
3964 use_graphics = TRUE;
3966 pict_wid = pict_hgt = 16;
3968 ANGBAND_GRAF = "new";
3977 Display *dpy = Metadpy->dpy;
3981 /* Load the graphical tiles */
3982 tiles_raw = ReadBMP(dpy, filename);
3984 /* Initialize the windows */
3985 for (i = 0; i < num_term; i++)
3987 term_data *td = &data[i];
3992 t->pict_hook = Term_pict_x11;
3994 /* Use graphics sometimes */
3995 t->higher_pict = TRUE;
3999 ResizeImage(dpy, tiles_raw,
4001 td->fnt->twid, td->fnt->hgt);
4004 /* Initialize the transparency masks */
4005 for (i = 0; i < num_term; i++)
4007 term_data *td = &data[i];
4009 int depth = DefaultDepth(dpy, DefaultScreen(dpy));
4010 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
4014 /* Determine total bytes needed for image */
4016 jj = (depth - 1) >> 2;
4017 while (jj >>= 1) ii <<= 1;
4018 total = td->fnt->twid * td->fnt->hgt * ii;
4021 TmpData = (char *)malloc(total);
4023 td->TmpImage = XCreateImage(dpy,visual,depth,
4024 ZPixmap, 0, TmpData,
4025 td->fnt->twid, td->fnt->hgt, 8, 0);
4029 /* Free tiles_raw? XXX XXX */
4032 #endif /* USE_GRAPHICS */
4039 #endif /* USE_X11 */