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.
13 * This file helps Angband work with UNIX/X11 computers.
15 * To use this file, compile with "USE_X11" defined, and link against all
16 * the various "X11" libraries which may be needed.
18 * See also "main-xaw.c".
20 * Part of this file provides a user interface package composed of several
21 * pseudo-objects, including "metadpy" (a display), "infowin" (a window),
22 * "infoclr" (a color), and "infofnt" (a font). Actually, the package was
23 * originally much more interesting, but it was bastardized to keep this
26 * The rest of this file is an implementation of "main-xxx.c" for X11.
28 * Most of this file is by Ben Harrison (benh@phial.com).
32 * The following shell script can be used to launch Angband, assuming that
33 * it was extracted into "~/Angband", and compiled using "USE_X11", on a
34 * Linux machine, with a 1280x1024 screen, using 6 windows (with the given
35 * characteristics), with gamma correction of 1.8 -> (1 / 1.8) * 256 = 142,
36 * and without graphics (add "-g" for graphics). Just copy this comment
37 * into a file, remove the leading " * " characters (and the head/tail of
38 * this comment), and make the file executable.
44 * echo "Launching angband..."
48 * setenv ANGBAND_X11_FONT_0 10x20
49 * setenv ANGBAND_X11_AT_X_0 5
50 * setenv ANGBAND_X11_AT_Y_0 510
53 * setenv ANGBAND_X11_FONT_1 8x13
54 * setenv ANGBAND_X11_AT_X_1 5
55 * setenv ANGBAND_X11_AT_Y_1 22
56 * setenv ANGBAND_X11_ROWS_1 35
59 * setenv ANGBAND_X11_FONT_2 8x13
60 * setenv ANGBAND_X11_AT_X_2 635
61 * setenv ANGBAND_X11_AT_Y_2 182
62 * setenv ANGBAND_X11_ROWS_2 23
65 * setenv ANGBAND_X11_FONT_3 8x13
66 * setenv ANGBAND_X11_AT_X_3 635
67 * setenv ANGBAND_X11_AT_Y_3 22
68 * setenv ANGBAND_X11_ROWS_3 12
70 * # Monster recall window
71 * setenv ANGBAND_X11_FONT_4 6x13
72 * setenv ANGBAND_X11_AT_X_4 817
73 * setenv ANGBAND_X11_AT_Y_4 847
74 * setenv ANGBAND_X11_COLS_4 76
75 * setenv ANGBAND_X11_ROWS_4 11
77 * # Object recall window
78 * setenv ANGBAND_X11_FONT_5 6x13
79 * setenv ANGBAND_X11_AT_X_5 817
80 * setenv ANGBAND_X11_AT_Y_5 520
81 * setenv ANGBAND_X11_COLS_5 76
82 * setenv ANGBAND_X11_ROWS_5 24
84 * # The build directory
88 * setenv ANGBAND_X11_GAMMA 142
91 * ./src/angband -mx11 -- -n6 &
99 #define uint unsigned int
106 #ifndef __MAKEDEPEND__
107 #include <X11/Xlib.h>
108 #include <X11/Xutil.h>
109 #include <X11/keysym.h>
110 #include <X11/keysymdef.h>
111 #endif /* __MAKEDEPEND__ */
115 * Include some helpful X11 code.
117 #include "maid-x11.h"
121 * Hack -- avoid some compiler warnings
123 #define IGNORE_UNUSED_FUNCTIONS
129 * 1) On a monochrome (or "fake-monochrome") display, all colors
130 * will be "cast" to "fg," except for the bg color, which is,
131 * obviously, cast to "bg". Thus, one can ignore this setting.
133 * 2) Because of the inner functioning of the color allocation
134 * routines, colors may be specified as (a) a typical color name,
135 * (b) a hexidecimal color specification (preceded by a pound sign),
136 * or (c) by strings such as "fg", "bg", "zg".
138 * 3) Due to the workings of the init routines, many colors
139 * may also be dealt with by their actual pixel values. Note that
140 * the pixel with all bits set is "zg = (1<<metadpy->depth)-1", which
141 * is not necessarily either black or white.
146 /**** Generic Types ****/
150 * An X11 pixell specifier
152 typedef unsigned long Pixell
;
155 * The structures defined below
157 typedef struct metadpy metadpy
;
158 typedef struct infowin infowin
;
159 typedef struct infoclr infoclr
;
160 typedef struct infofnt infofnt
;
164 * A structure summarizing a given Display.
166 * - The Display itself
167 * - The default Screen for the display
168 * - The virtual root (usually just the root)
169 * - The default colormap (from a macro)
171 * - The "name" of the display
173 * - The socket to listen to for events
175 * - The width of the display screen (from a macro)
176 * - The height of the display screen (from a macro)
177 * - The bit depth of the display screen (from a macro)
179 * - The black Pixell (from a macro)
180 * - The white Pixell (from a macro)
182 * - The background Pixell (default: black)
183 * - The foreground Pixell (default: white)
184 * - The maximal Pixell (Equals: ((2 ^ depth)-1), is usually ugly)
186 * - Bit Flag: Force all colors to black and white (default: !color)
187 * - Bit Flag: Allow the use of color (default: depth > 1)
188 * - Bit Flag: We created 'dpy', and so should nuke it when done.
220 * A Structure summarizing Window Information.
222 * I assume that a window is at most 30000 pixels on a side.
223 * I assume that the root windw is also at most 30000 square.
226 * - The current Input Event Mask
228 * - The location of the window
229 * - The saved (startup) location of the window
230 * - The width, height of the window
231 * - The border width of this window
233 * - Byte: 1st Extra byte
235 * - Bit Flag: This window is currently Mapped
236 * - Bit Flag: This window needs to be redrawn
237 * - Bit Flag: This window has been resized
239 * - Bit Flag: We should nuke 'win' when done with it
241 * - Bit Flag: 1st extra flag
242 * - Bit Flag: 2nd extra flag
243 * - Bit Flag: 3rd extra flag
244 * - Bit Flag: 4th extra flag
278 * A Structure summarizing Operation+Color Information
280 * - The actual GC corresponding to this info
282 * - The Foreground Pixell Value
283 * - The Background Pixell Value
285 * - Num (0-15): The operation code (As in Clear, Xor, etc)
286 * - Bit Flag: The GC is in stipple mode
287 * - Bit Flag: Destroy 'gc' at Nuke time.
304 * A Structure to Hold Font Information
306 * - The 'XFontStruct*' (yields the 'Font')
310 * - The default character width
311 * - The default character height
312 * - The default character ascent
314 * - Byte: Pixel offset used during fake mono
316 * - Flag: Force monospacing via 'wid'
317 * - Flag: Nuke info when done
341 typedef struct term_data term_data
;
344 * A structure for each "term"
358 /* Temporary storage for overlaying tiles. */
362 int tile_wid2
; /* Tile-width with bigscreen */
365 #endif /* USE_GRAPHICS */
367 /* Pointers to allocated data, needed to clear up memory */
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
);
465 static infoclr
*Infoclr
= (infoclr
*)(NULL
);
466 static infofnt
*Infofnt
= (infofnt
*)(NULL
);
472 static infoclr
*clr
[MAX_COLORS
];
476 /**** Generic code ****/
480 * Init the current metadpy, with various initialization stuff.
483 * dpy: The Display* to use (if NULL, create it)
484 * name: The name of the Display (if NULL, the current)
487 * If 'name' is NULL, but 'dpy' is set, extract name from dpy
488 * If 'dpy' is NULL, then Create the named Display
489 * If 'name' is NULL, and so is 'dpy', use current Display
491 * Return -1 if no Display given, and none can be opened.
493 static errr
Metadpy_init_2(Display
*dpy
, cptr name
)
495 metadpy
*m
= Metadpy
;
497 /*** Open the display if needed ***/
499 /* If no Display given, attempt to Create one */
502 /* Attempt to open the display */
503 dpy
= XOpenDisplay(name
);
506 if (!dpy
) return (-1);
508 /* We will have to nuke it when done */
512 /* Since the Display was given, use it */
515 /* We will not have to nuke it when done */
520 /*** Save some information ***/
522 /* Save the Display itself */
525 /* Get the Screen and Virtual Root Window */
526 m
->screen
= DefaultScreenOfDisplay(dpy
);
527 m
->root
= RootWindowOfScreen(m
->screen
);
529 /* Get the default colormap */
530 m
->cmap
= DefaultColormapOfScreen(m
->screen
);
532 /* Extract the true name of the display */
533 m
->name
= DisplayString(dpy
);
536 m
->fd
= ConnectionNumber(Metadpy
->dpy
);
538 /* Save the Size and Depth of the screen */
539 m
->width
= WidthOfScreen(m
->screen
);
540 m
->height
= HeightOfScreen(m
->screen
);
541 m
->depth
= DefaultDepthOfScreen(m
->screen
);
543 /* Save the Standard Colors */
544 m
->black
= BlackPixelOfScreen(m
->screen
);
545 m
->white
= WhitePixelOfScreen(m
->screen
);
547 /*** Make some clever Guesses ***/
549 /* Guess at the desired 'fg' and 'bg' Pixell's */
553 /* Calculate the Maximum allowed Pixel value. */
554 m
->zg
= ((Pixell
)1 << m
->depth
) - 1;
556 /* Save various default Flag Settings */
557 m
->color
= ((m
->depth
> 1) ? 1 : 0);
558 m
->mono
= ((m
->color
) ? 0 : 1);
560 /* Return "success" */
566 * Nuke the current metadpy
568 static errr
Metadpy_nuke(void)
570 metadpy
*m
= Metadpy
;
573 /* If required, Free the Display */
576 /* Close the Display */
577 XCloseDisplay(m
->dpy
);
579 /* Forget the Display */
580 m
->dpy
= (Display
*)(NULL
);
582 /* Do not nuke it again */
592 * General Flush/ Sync/ Discard routine
594 static errr
Metadpy_update(int flush
, int sync
, int discard
)
596 /* Flush if desired */
597 if (flush
) XFlush(Metadpy
->dpy
);
599 /* Sync if desired, using 'discard' */
600 if (sync
) XSync(Metadpy
->dpy
, discard
);
610 static errr
Metadpy_do_beep(void)
612 /* Make a simple beep */
613 XBell(Metadpy
->dpy
, 100);
621 * Set the name (in the title bar) of Infowin
623 static errr
Infowin_set_name(cptr name
)
629 my_strcpy(buf
, name
, sizeof(buf
));
630 st
= XStringListToTextProperty(&bp
, 1, &tp
);
631 if (st
) XSetWMName(Metadpy
->dpy
, Infowin
->win
, &tp
);
636 #ifndef IGNORE_UNUSED_FUNCTIONS
639 * Set the icon name of Infowin
641 static errr
Infowin_set_icon_name(cptr name
)
647 my_strcpy(buf
, name
, sizeof(buf
));
648 st
= XStringListToTextProperty(&bp
, 1, &tp
);
649 if (st
) XSetWMIconName(Metadpy
->dpy
, Infowin
->win
, &tp
);
653 #endif /* IGNORE_UNUSED_FUNCTIONS */
659 static errr
Infowin_nuke(void)
661 infowin
*iwin
= Infowin
;
663 /* Nuke if requested */
666 /* Destory the old window */
667 XDestroyWindow(Metadpy
->dpy
, iwin
->win
);
676 * Prepare a new 'infowin'.
678 static errr
Infowin_prepare(Window xid
)
680 infowin
*iwin
= Infowin
;
683 XWindowAttributes xwa
;
685 unsigned int w
, h
, b
, d
;
690 /* Check For Error XXX Extract some ACTUAL data from 'xid' */
691 XGetGeometry(Metadpy
->dpy
, xid
, &tmp_win
, &x
, &y
, &w
, &h
, &b
, &d
);
693 /* Apply the above info */
702 /* Check Error XXX Extract some more ACTUAL data */
703 XGetWindowAttributes(Metadpy
->dpy
, xid
, &xwa
);
705 /* Apply the above info */
706 iwin
->mask
= xwa
.your_event_mask
;
707 iwin
->mapped
= ((xwa
.map_state
== IsUnmapped
) ? 0 : 1);
709 /* And assume that we are exposed */
717 #ifndef IGNORE_UNUSED_FUNCTIONS
720 * Initialize a new 'infowin'.
722 static errr
Infowin_init_real(Window xid
)
725 (void)WIPE(Infowin
, infowin
);
727 /* Start out non-nukable */
730 /* Attempt to Prepare ourself */
731 return (Infowin_prepare(xid
));
734 #endif /* IGNORE_UNUSED_FUNCTIONS */
738 * Init an infowin by giving some data.
741 * dad: The Window that should own this Window (if any)
742 * x,y: The position of this Window
743 * w,h: The size of this Window
744 * b,d: The border width and pixel depth
747 * If 'dad == None' assume 'dad == root'
749 static errr
Infowin_init_data(Window dad
, int x
, int y
, int w
, int h
,
750 int b
, Pixell fg
, Pixell bg
)
755 (void)WIPE(Infowin
, infowin
);
758 /*** Error Check XXX ***/
761 /*** Create the Window 'xid' from data ***/
763 /* What happened here? XXX XXX XXX */
765 /* If no parent given, depend on root */
768 /* #ifdef USE_GRAPHICS
770 xid = XCreateWindow(Metadpy->dpy, Metadpy->root, x, y, w, h, b, 8, InputOutput, CopyFromParent, 0, 0);
781 /* Create the Window XXX Error Check */
782 xid
= XCreateSimpleWindow(Metadpy
->dpy
, dad
, x
, y
, w
, h
, b
, fg
, bg
);
784 /* Start out selecting No events */
785 XSelectInput(Metadpy
->dpy
, xid
, 0L);
788 /*** Prepare the new infowin ***/
790 /* Mark it as nukable */
793 /* Attempt to Initialize the infowin */
794 return (Infowin_prepare(xid
));
800 * Modify the event mask of an Infowin
802 static errr
Infowin_set_mask(long mask
)
804 /* Save the new setting */
805 Infowin
->mask
= mask
;
807 /* Execute the Mapping */
808 XSelectInput(Metadpy
->dpy
, Infowin
->win
, Infowin
->mask
);
816 * Request that Infowin be mapped
818 static errr
Infowin_map(void)
820 /* Execute the Mapping */
821 XMapWindow(Metadpy
->dpy
, Infowin
->win
);
828 #ifndef IGNORE_UNUSED_FUNCTIONS
831 * Request that Infowin be unmapped
833 static errr
Infowin_unmap(void)
835 /* Execute the Un-Mapping */
836 XUnmapWindow(Metadpy
->dpy
, Infowin
->win
);
842 #endif /* IGNORE_UNUSED_FUNCTIONS */
846 * Request that Infowin be raised
848 static errr
Infowin_raise(void)
850 /* Raise towards visibility */
851 XRaiseWindow(Metadpy
->dpy
, Infowin
->win
);
858 #ifndef IGNORE_UNUSED_FUNCTIONS
861 * Request that Infowin be lowered
863 static errr
Infowin_lower(void)
865 /* Lower towards invisibility */
866 XLowerWindow(Metadpy
->dpy
, Infowin
->win
);
872 #endif /* IGNORE_UNUSED_FUNCTIONS */
876 * Request that Infowin be moved to a new location
878 static errr
Infowin_impell(int x
, int y
)
880 /* Execute the request */
881 XMoveWindow(Metadpy
->dpy
, Infowin
->win
, x
, y
);
891 static errr
Infowin_resize(int w
, int h
)
893 /* Execute the request */
894 XResizeWindow(Metadpy
->dpy
, Infowin
->win
, w
, h
);
901 #ifndef IGNORE_UNUSED_FUNCTIONS
904 * Move and Resize an infowin
906 static errr
Infowin_locate(int x
, int y
, int w
, int h
)
908 /* Execute the request */
909 XMoveResizeWindow(Metadpy
->dpy
, Infowin
->win
, x
, y
, w
, h
);
915 #endif /* IGNORE_UNUSED_FUNCTIONS */
919 * Visually clear Infowin
921 static errr
Infowin_wipe(void)
923 /* Execute the request */
924 XClearWindow(Metadpy
->dpy
, Infowin
->win
);
931 #ifndef IGNORE_UNUSED_FUNCTIONS
934 * Visually Paint Infowin with the current color
936 static errr
Infowin_fill(void)
938 /* Execute the request */
939 XFillRectangle(Metadpy
->dpy
, Infowin
->win
, Infoclr
->gc
,
940 0, 0, Infowin
->w
, Infowin
->h
);
946 #endif /* IGNORE_UNUSED_FUNCTIONS */
950 * A NULL terminated pair list of legal "operation names"
952 * Pairs of values, first is texttual name, second is the string
953 * holding the decimal value that the operation corresponds to.
955 static cptr opcode_pairs
[] =
974 "+copyInverted", "12",
982 * Parse a word into an operation "code"
985 * str: A string, hopefully representing an Operation
988 * 0-15: if 'str' is a valid Operation
989 * -1: if 'str' could not be parsed
991 static int Infoclr_Opcode(cptr str
)
995 /* Scan through all legal operation names */
996 for (i
= 0; opcode_pairs
[i
*2]; ++i
)
998 /* Is this the right oprname? */
999 if (streq(opcode_pairs
[i
*2], str
))
1001 /* Convert the second element in the pair into a Code */
1002 return (atoi(opcode_pairs
[i
*2+1]));
1006 /* The code was not found, return -1 */
1011 #ifndef IGNORE_UNUSED_FUNCTIONS
1014 * Request a Pixell by name. Note: uses 'Metadpy'.
1017 * name: The name of the color to try to load (see below)
1020 * The Pixell value that metched the given name
1021 * 'Metadpy->fg' if the name was unparseable
1023 * Valid forms for 'name':
1024 * 'fg', 'bg', 'zg', '<name>' and '#<code>'
1026 static Pixell
Infoclr_Pixell(cptr name
)
1030 /* Attempt to Parse the name */
1031 if (name
&& name
[0])
1033 /* The 'bg' color is available */
1034 if (streq(name
, "bg")) return (Metadpy
->bg
);
1036 /* The 'fg' color is available */
1037 if (streq(name
, "fg")) return (Metadpy
->fg
);
1039 /* The 'zg' color is available */
1040 if (streq(name
, "zg")) return (Metadpy
->zg
);
1042 /* The 'white' color is available */
1043 if (streq(name
, "white")) return (Metadpy
->white
);
1045 /* The 'black' color is available */
1046 if (streq(name
, "black")) return (Metadpy
->black
);
1048 /* Attempt to parse 'name' into 'scrn' */
1049 if (!(XParseColor(Metadpy
->dpy
, Metadpy
->cmap
, name
, &scrn
)))
1051 plog_fmt("Warning: Couldn't parse color '%s'\n", name
);
1054 /* Attempt to Allocate the Parsed color */
1055 if (!(XAllocColor(Metadpy
->dpy
, Metadpy
->cmap
, &scrn
)))
1057 plog_fmt("Warning: Couldn't allocate color '%s'\n", name
);
1060 /* The Pixel was Allocated correctly */
1061 else return (scrn
.pixel
);
1064 /* Warn about the Default being Used */
1065 plog_fmt("Warning: Using 'fg' for unknown color '%s'\n", name
);
1067 /* Default to the 'Foreground' color */
1068 return (Metadpy
->fg
);
1073 * Initialize a new 'infoclr' with a real GC.
1075 static errr
Infoclr_init_1(GC gc
)
1077 infoclr
*iclr
= Infoclr
;
1079 /* Wipe the iclr clean */
1080 (void)WIPE(iclr
, infoclr
);
1089 #endif /* IGNORE_UNUSED_FUNCTIONS */
1093 * Nuke an old 'infoclr'.
1095 static errr
Infoclr_nuke(void)
1097 infoclr
*iclr
= Infoclr
;
1099 /* Deal with 'GC' */
1103 XFreeGC(Metadpy
->dpy
, iclr
->gc
);
1106 /* Forget the current */
1107 Infoclr
= (infoclr
*)(NULL
);
1115 * Initialize an infoclr with some data
1118 * fg: The Pixell for the requested Foreground (see above)
1119 * bg: The Pixell for the requested Background (see above)
1120 * op: The Opcode for the requested Operation (see above)
1121 * stip: The stipple mode
1123 static errr
Infoclr_init_data(Pixell fg
, Pixell bg
, int op
, int stip
)
1125 infoclr
*iclr
= Infoclr
;
1129 unsigned long gc_mask
;
1133 /*** Simple error checking of opr and clr ***/
1135 /* Check the 'Pixells' for realism */
1136 if (bg
> Metadpy
->zg
) return (-1);
1137 if (fg
> Metadpy
->zg
) return (-1);
1139 /* Check the data for trueness */
1140 if ((op
< 0) || (op
> 15)) return (-1);
1143 /*** Create the requested 'GC' ***/
1145 /* Assign the proper GC function */
1148 /* Assign the proper GC background */
1149 gcv
.background
= bg
;
1151 /* Assign the proper GC foreground */
1152 gcv
.foreground
= fg
;
1154 /* Hack -- Handle XOR (xor is code 6) by hacking bg and fg */
1155 if (op
== 6) gcv
.background
= 0;
1156 if (op
== 6) gcv
.foreground
= (bg
^ fg
);
1158 /* Assign the proper GC Fill Style */
1159 gcv
.fill_style
= (stip
? FillStippled
: FillSolid
);
1161 /* Turn off 'Give exposure events for pixmap copying' */
1162 gcv
.graphics_exposures
= False
;
1164 /* Set up the GC mask */
1165 gc_mask
= (GCFunction
| GCBackground
| GCForeground
|
1166 GCFillStyle
| GCGraphicsExposures
);
1168 /* Create the GC detailed above */
1169 gc
= XCreateGC(Metadpy
->dpy
, Metadpy
->root
, gc_mask
, &gcv
);
1172 /*** Initialize ***/
1174 /* Wipe the iclr clean */
1175 (void)WIPE(iclr
, infoclr
);
1180 /* Nuke it when done */
1183 /* Assign the parms */
1187 iclr
->stip
= stip
? 1 : 0;
1196 * Change the 'fg' for an infoclr
1199 * fg: The Pixell for the requested Foreground (see above)
1201 static errr
Infoclr_change_fg(Pixell fg
)
1203 infoclr
*iclr
= Infoclr
;
1206 /*** Simple error checking of opr and clr ***/
1208 /* Check the 'Pixells' for realism */
1209 if (fg
> Metadpy
->zg
) return (-1);
1215 XSetForeground(Metadpy
->dpy
, iclr
->gc
, fg
);
1224 * Nuke an old 'infofnt'.
1226 static errr
Infofnt_nuke(void)
1228 infofnt
*ifnt
= Infofnt
;
1230 /* Deal with 'name' */
1234 string_free(ifnt
->name
);
1237 /* Nuke info if needed */
1241 XFreeFont(Metadpy
->dpy
, ifnt
->info
);
1250 * Prepare a new 'infofnt'
1252 static errr
Infofnt_prepare(XFontStruct
*info
)
1254 infofnt
*ifnt
= Infofnt
;
1258 /* Assign the struct */
1261 /* Jump into the max bouonds thing */
1262 cs
= &(info
->max_bounds
);
1264 /* Extract default sizing info */
1265 ifnt
->asc
= info
->ascent
;
1266 ifnt
->hgt
= info
->ascent
+ info
->descent
;
1267 ifnt
->wid
= cs
->width
;
1268 ifnt
->twid
= cs
->width
;
1275 #ifndef IGNORE_UNUSED_FUNCTIONS
1278 * Initialize a new 'infofnt'.
1280 static errr
Infofnt_init_real(XFontStruct
*info
)
1282 /* Wipe the thing */
1283 (void)WIPE(Infofnt
, infofnt
);
1288 /* Attempt to prepare it */
1289 return (Infofnt_prepare(info
));
1292 #endif /* IGNORE_UNUSED_FUNCTIONS */
1296 * Init an infofnt by its Name
1299 * name: The name of the requested Font
1301 static errr
Infofnt_init_data(cptr name
)
1306 /*** Load the info Fresh, using the name ***/
1308 /* If the name is not given, report an error */
1309 if (!name
) return (-1);
1311 /* Attempt to load the font */
1312 info
= XLoadQueryFont(Metadpy
->dpy
, name
);
1314 /* The load failed, try to recover */
1315 if (!info
) return (-1);
1318 /*** Init the font ***/
1320 /* Wipe the thing */
1321 (void)WIPE(Infofnt
, infofnt
);
1323 /* Attempt to prepare it */
1324 if (Infofnt_prepare(info
))
1327 XFreeFont(Metadpy
->dpy
, info
);
1333 /* Save a copy of the font name */
1334 Infofnt
->name
= string_make(name
);
1336 /* Mark it as nukable */
1339 /* HACK - force all fonts to be printed character by character */
1350 static errr
Infofnt_text_std(int x
, int y
, cptr str
, int len
)
1355 term_data
*td
= (term_data
*)(Term
->data
);
1357 /*** Do a brief info analysis ***/
1359 /* Do nothing if the string is null */
1360 if (!str
|| !*str
) return (-1);
1362 /* Get the length of the string */
1363 if (len
< 0) len
= strlen(str
);
1365 /*** Decide where to place the string, vertically ***/
1367 /* Ignore Vertical Justifications */
1368 y
= (y
* td
->tile_hgt
) + Infowin
->oy
;
1371 /*** Decide where to place the string, horizontally ***/
1373 /* Line up with x at left edge of column 'x' */
1374 x
= (x
* td
->tile_wid
) + Infowin
->ox
;
1377 /*** Erase the background ***/
1379 /* The total width will be 'len' chars * standard width */
1380 w
= len
* td
->tile_wid
;
1382 /* Simply do 'td->tile_hgt' (a single row) high */
1385 /* Fill the background */
1386 XFillRectangle(Metadpy
->dpy
, Infowin
->win
, clr
[TERM_DARK
]->gc
, x
, y
, w
, h
);
1389 /*** Actually draw 'str' onto the infowin ***/
1391 /* Be sure the correct font is ready */
1392 XSetFont(Metadpy
->dpy
, Infoclr
->gc
, Infofnt
->info
->fid
);
1398 /*** Handle the fake mono we can enforce on fonts ***/
1400 /* Monotize the font */
1403 /* Do each character */
1404 for (i
= 0; i
< len
; ++i
)
1406 /* Note that the Infoclr is set up to contain the Infofnt */
1407 XDrawImageString(Metadpy
->dpy
, Infowin
->win
, Infoclr
->gc
,
1408 x
+ i
* td
->tile_wid
+ Infofnt
->off
, y
, str
+ i
, 1);
1412 /* Assume monospaced font */
1415 /* Note that the Infoclr is set up to contain the Infofnt */
1416 XDrawImageString(Metadpy
->dpy
, Infowin
->win
, Infoclr
->gc
,
1426 * Painting where text would be
1428 static errr
Infofnt_text_non(int x
, int y
, cptr str
, int len
)
1432 term_data
*td
= (term_data
*)(Term
->data
);
1434 /*** Find the width ***/
1436 /* Negative length is a flag to count the characters in str */
1437 if (len
< 0) len
= strlen(str
);
1439 /* The total width will be 'len' chars * standard width */
1440 w
= len
* td
->tile_wid
;
1443 /*** Find the X dimensions ***/
1445 /* Line up with x at left edge of column 'x' */
1446 x
= x
* td
->tile_wid
+ Infowin
->ox
;
1449 /*** Find other dimensions ***/
1451 /* Simply do 'td->tile_hgt' (a single row) high */
1454 /* Simply do "at top" in row 'y' */
1455 y
= y
* h
+ Infowin
->oy
;
1458 /*** Actually 'paint' the area ***/
1460 /* Just do a Fill Rectangle */
1461 XFillRectangle(Metadpy
->dpy
, Infowin
->win
, Infoclr
->gc
, x
, y
, w
, h
);
1469 /*************************************************************************/
1473 * Angband specific code follows... (ANGBAND)
1478 * Hack -- cursor color
1480 static infoclr
*xor;
1484 * Color info (unused, red, green, blue).
1486 static byte color_table
[MAX_COLORS
][4];
1490 * The number of term data structures
1492 #define MAX_TERM_DATA 8
1495 * The array of term data structures
1497 static term_data data
[MAX_TERM_DATA
];
1501 * Path to the X11 settings file
1503 char settings
[1024];
1508 * Remember the number of terminal windows open
1510 static int term_windows_open
;
1515 * Process a keypress event
1517 * Also appears in "main-xaw.c".
1519 static void react_keypress(XKeyEvent
*ev
)
1521 int i
, n
, mc
, ms
, mo
, mx
;
1531 /* Check for "normal" keypresses */
1532 n
= XLookupString(ev
, buf
, 125, &ks
, NULL
);
1538 /* Hack -- Ignore "modifier keys" */
1539 if (IsModifierKey(ks
)) return;
1542 /* Hack -- convert into an unsigned int */
1545 /* Extract four "modifier flags" */
1546 mc
= (ev
->state
& ControlMask
) ? TRUE
: FALSE
;
1547 ms
= (ev
->state
& ShiftMask
) ? TRUE
: FALSE
;
1548 mo
= (ev
->state
& Mod1Mask
) ? TRUE
: FALSE
;
1549 mx
= (ev
->state
& Mod2Mask
) ? TRUE
: FALSE
;
1552 /* Normal keys with no modifiers */
1553 if (n
&& !mo
&& !mx
&& !IsSpecialKey(ks
))
1555 /* Enqueue the normal key(s) */
1556 for (i
= 0; buf
[i
]; i
++) Term_keypress(buf
[i
]);
1563 /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1568 Term_keypress(ESCAPE
);
1574 Term_keypress('\r');
1580 Term_keypress('\t');
1587 Term_keypress('\010');
1593 /* Hack -- Use the KeySym */
1596 strnfmt(msg
, sizeof(msg
), "%c%s%s%s%s_%lX%c", 31,
1597 mc
? "N" : "", ms
? "S" : "",
1598 mo
? "O" : "", mx
? "M" : "",
1599 (unsigned long)(ks
), 13);
1602 /* Hack -- Use the Keycode */
1605 strnfmt(msg
, sizeof(msg
), "%c%s%s%s%sK_%X%c", 31,
1606 mc
? "N" : "", ms
? "S" : "",
1607 mo
? "O" : "", mx
? "M" : "",
1611 /* Enqueue the "macro trigger" string */
1612 for (i
= 0; msg
[i
]; i
++) Term_keypress(msg
[i
]);
1615 /* Hack -- auto-define macros as needed */
1616 if (n
&& (macro_find_exact(msg
) < 0))
1618 /* Create a macro */
1619 macro_add(msg
, buf
);
1625 * Find the square a particular pixel is part of.
1627 static void pixel_to_square(int * const x
, int * const y
,
1628 const int ox
, const int oy
)
1630 term_data
*td
= (term_data
*)(Term
->data
);
1632 (*x
) = (ox
- Infowin
->ox
) / td
->tile_wid
;
1633 (*y
) = (oy
- Infowin
->oy
) / td
->tile_hgt
;
1642 static errr
CheckEvent(bool wait
)
1644 term_data
*old_td
= (term_data
*)(Term
->data
);
1646 XEvent xev_body
, *xev
= &xev_body
;
1648 term_data
*td
= NULL
;
1649 infowin
*iwin
= NULL
;
1654 /* Do not wait unless requested */
1655 if (!wait
&& !XPending(Metadpy
->dpy
)) return (1);
1657 /* Load the Event */
1658 XNextEvent(Metadpy
->dpy
, xev
);
1661 /* Notice new keymaps */
1662 if (xev
->type
== MappingNotify
)
1664 XRefreshKeyboardMapping(&xev
->xmapping
);
1669 /* Scan the windows */
1670 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
1672 if (xev
->xany
.window
== data
[i
].win
->win
)
1681 /* Unknown window */
1682 if (!td
|| !iwin
) return (0);
1685 /* Hack -- activate the Term */
1686 Term_activate(&td
->t
);
1688 /* Hack -- activate the window */
1692 /* Switch on the Type */
1697 bool press
= (xev
->type
== ButtonPress
);
1701 /* Where is the mouse */
1702 int x
= xev
->xbutton
.x
;
1703 int y
= xev
->xbutton
.y
;
1705 /* Which button is involved */
1706 if (xev
->xbutton
.button
== Button1
) z
= 1;
1707 else if (xev
->xbutton
.button
== Button2
) z
= 2;
1708 else if (xev
->xbutton
.button
== Button3
) z
= 3;
1709 else if (xev
->xbutton
.button
== Button4
) z
= 4;
1710 else if (xev
->xbutton
.button
== Button5
) z
= 5;
1713 /* The co-ordinates are only used in Angband format. */
1714 pixel_to_square(&x
, &y
, x
, y
);
1715 if (press
) Term_mousepress(x
, y
, z
);
1723 /* Where is the mouse */
1724 int x
= xev
->xmotion
.x
;
1725 int y
= xev
->xmotion
.y
;
1726 unsigned int z
= xev
->xmotion
.state
;
1728 /* Convert to co-ordinates Angband understands. */
1729 pixel_to_square(&x
, &y
, x
, y
);
1737 /* Save the mouse location */
1741 /* Hack -- use "old" term */
1742 Term_activate(&old_td
->t
);
1744 /* Process the key */
1745 react_keypress(&(xev
->xkey
));
1754 x1
= (xev
->xexpose
.x
- Infowin
->ox
) / td
->tile_wid
;
1755 x2
= (xev
->xexpose
.x
+ xev
->xexpose
.width
- Infowin
->ox
) / td
->tile_wid
;
1757 y1
= (xev
->xexpose
.y
- Infowin
->oy
) / td
->tile_hgt
;
1758 y2
= (xev
->xexpose
.y
+ xev
->xexpose
.height
- Infowin
->oy
) / td
->tile_hgt
;
1760 Term_redraw_section(x1
, y1
, x2
, y2
);
1767 Infowin
->mapped
= 1;
1768 Term
->mapped_flag
= TRUE
;
1774 Infowin
->mapped
= 0;
1775 Term
->mapped_flag
= FALSE
;
1779 /* Move and/or Resize */
1780 case ConfigureNotify
:
1782 int cols
, rows
, wid
, hgt
;
1784 int ox
= Infowin
->ox
;
1785 int oy
= Infowin
->oy
;
1787 /* Save the new Window Parms */
1788 Infowin
->x
= xev
->xconfigure
.x
;
1789 Infowin
->y
= xev
->xconfigure
.y
;
1790 Infowin
->w
= xev
->xconfigure
.width
;
1791 Infowin
->h
= xev
->xconfigure
.height
;
1793 /* Determine "proper" number of rows/cols */
1794 cols
= ((Infowin
->w
- (ox
+ ox
)) / td
->tile_wid
);
1795 rows
= ((Infowin
->h
- (oy
+ oy
)) / td
->tile_hgt
);
1797 /* Hack -- minimal size */
1798 if (cols
< 1) cols
= 1;
1799 if (rows
< 1) rows
= 1;
1803 /* Hack the main window must be at least 80x24 */
1804 if (cols
< 80) cols
= 80;
1805 if (rows
< 24) rows
= 24;
1808 /* Desired size of window */
1809 wid
= cols
* td
->tile_wid
+ (ox
+ ox
);
1810 hgt
= rows
* td
->tile_hgt
+ (oy
+ oy
);
1812 /* Resize the Term (if needed) */
1813 (void)Term_resize(cols
, rows
);
1815 /* Resize the windows if any "change" is needed */
1816 if ((Infowin
->w
!= wid
) || (Infowin
->h
!= hgt
))
1819 Infowin_set(td
->win
);
1820 Infowin_resize(wid
, hgt
);
1828 /* Hack -- Activate the old term */
1829 Term_activate(&old_td
->t
);
1831 /* Hack -- Activate the proper window */
1832 Infowin_set(old_td
->win
);
1841 * Handle "activation" of a term
1843 static errr
Term_xtra_x11_level(int v
)
1845 term_data
*td
= (term_data
*)(Term
->data
);
1847 /* Handle "activate" */
1850 /* Activate the window */
1851 Infowin_set(td
->win
);
1853 /* Activate the font */
1854 Infofnt_set(td
->fnt
);
1865 static errr
Term_xtra_x11_react(void)
1871 /* Check the colors */
1872 for (i
= 0; i
< MAX_COLORS
; i
++)
1874 if ((color_table
[i
][0] != angband_color_table
[i
][0]) ||
1875 (color_table
[i
][1] != angband_color_table
[i
][1]) ||
1876 (color_table
[i
][2] != angband_color_table
[i
][2]) ||
1877 (color_table
[i
][3] != angband_color_table
[i
][3]))
1881 /* Save new values */
1882 color_table
[i
][0] = angband_color_table
[i
][0];
1883 color_table
[i
][1] = angband_color_table
[i
][1];
1884 color_table
[i
][2] = angband_color_table
[i
][2];
1885 color_table
[i
][3] = angband_color_table
[i
][3];
1888 pixel
= create_pixel(Metadpy
->dpy
,
1893 /* Change the foreground */
1894 Infoclr_set(clr
[i
]);
1895 Infoclr_change_fg(pixel
);
1906 * Handle a "special request"
1908 static errr
Term_xtra_x11(int n
, int v
)
1910 /* Handle a subset of the legal requests */
1914 case TERM_XTRA_NOISE
: Metadpy_do_beep(); return (0);
1916 /* Flush the output XXX XXX */
1917 case TERM_XTRA_FRESH
: Metadpy_update(1, 0, 0); return (0);
1919 /* Process random events XXX */
1920 case TERM_XTRA_BORED
: return (CheckEvent(0));
1922 /* Process Events XXX */
1923 case TERM_XTRA_EVENT
: return (CheckEvent(v
));
1925 /* Flush the events XXX */
1926 case TERM_XTRA_FLUSH
: while (!CheckEvent(FALSE
)); return (0);
1928 /* Handle change in the "level" */
1929 case TERM_XTRA_LEVEL
: return (Term_xtra_x11_level(v
));
1931 /* Clear the screen */
1932 case TERM_XTRA_CLEAR
: Infowin_wipe(); return (0);
1934 /* Delay for some milliseconds */
1935 case TERM_XTRA_DELAY
:
1936 if (v
> 0) usleep(1000 * v
);
1939 /* React to changes */
1940 case TERM_XTRA_REACT
: return (Term_xtra_x11_react());
1949 * Draw the cursor as a rectangular outline
1951 static errr
Term_curs_x11(int x
, int y
)
1953 term_data
*td
= (term_data
*)(Term
->data
);
1955 XDrawRectangle(Metadpy
->dpy
, Infowin
->win
, xor->gc
,
1956 x
* td
->tile_wid
+ Infowin
->ox
,
1957 y
* td
->tile_hgt
+ Infowin
->oy
,
1958 td
->tile_wid
- 1, td
->tile_hgt
- 1);
1966 * Draw the double width cursor as a rectangular outline
1968 static errr
Term_bigcurs_x11(int x
, int y
)
1970 term_data
*td
= (term_data
*)(Term
->data
);
1972 XDrawRectangle(Metadpy
->dpy
, Infowin
->win
, xor->gc
,
1973 x
* td
->tile_wid
+ Infowin
->ox
,
1974 y
* td
->tile_hgt
+ Infowin
->oy
,
1975 td
->tile_wid2
- 1, td
->tile_hgt
- 1);
1983 * Erase some characters.
1985 static errr
Term_wipe_x11(int x
, int y
, int n
)
1987 /* Erase (use black) */
1988 Infoclr_set(clr
[TERM_DARK
]);
1990 /* Mega-Hack -- Erase some space */
1991 Infofnt_text_non(x
, y
, "", n
);
1999 * Draw some textual characters.
2001 static errr
Term_text_x11(int x
, int y
, int n
, byte a
, cptr s
)
2004 Infoclr_set(clr
[a
]);
2007 Infofnt_text_std(x
, y
, s
, n
);
2017 * Draw some graphical characters.
2019 static errr
Term_pict_x11(int x
, int y
, int n
, const byte
*ap
, const char *cp
, const byte
*tap
, const char *tcp
)
2033 unsigned long pixel
, blank
;
2035 term_data
*td
= (term_data
*)(Term
->data
);
2040 /* Add in affect of window boundaries */
2044 for (i
= 0; i
< n
; ++i
)
2052 /* For extra speed - cache these values */
2053 x1
= (c
& 0x7F) * td
->tile_wid2
;
2054 y1
= (a
& 0x7F) * td
->tile_hgt
;
2056 /* For extra speed - cache these values */
2057 x2
= (tc
& 0x7F) * td
->tile_wid2
;
2058 y2
= (ta
& 0x7F) * td
->tile_hgt
;
2060 /* Optimise the common case */
2061 if (((x1
== x2
) && (y1
== y2
)) ||
2062 !(((byte
)ta
& 0x80) && ((byte
)tc
& 0x80)))
2064 /* Draw object / terrain */
2065 XPutImage(Metadpy
->dpy
, td
->win
->win
,
2070 td
->tile_wid2
, td
->tile_hgt
);
2074 /* Mega Hack^2 - assume the top left corner is "blank" */
2075 if (arg_graphics
== GRAPHICS_DAVID_GERVAIS
)
2076 blank
= XGetPixel(td
->tiles
, 0, 0);
2078 blank
= XGetPixel(td
->tiles
, 0, td
->tile_hgt
* 6);
2080 for (k
= 0; k
< td
->tile_wid2
; k
++)
2082 for (l
= 0; l
< td
->tile_hgt
; l
++)
2084 /* If mask set... */
2085 if ((pixel
= XGetPixel(td
->tiles
, x1
+ k
, y1
+ l
)) == blank
)
2087 /* Output from the terrain */
2088 pixel
= XGetPixel(td
->tiles
, x2
+ k
, y2
+ l
);
2094 /* Store into the temp storage. */
2095 XPutPixel(td
->TmpImage
, k
, l
, pixel
);
2100 /* Draw to screen */
2101 XPutImage(Metadpy
->dpy
, td
->win
->win
,
2105 td
->tile_wid2
, td
->tile_hgt
);
2115 #endif /* USE_GRAPHICS */
2118 static void save_prefs(void)
2123 /* Open the settings file */
2124 fff
= my_fopen(settings
, "w");
2130 fprintf(fff
, "# %s X11 settings\n\n", VERSION_NAME
);
2132 /* Number of term windows to open */
2133 fprintf(fff
, "TERM_WINS=%d\n\n", term_windows_open
);
2135 /* Save window prefs */
2136 for (i
= 0; i
< MAX_TERM_DATA
; i
++)
2138 term_data
*td
= &data
[i
];
2140 if (!td
->t
.mapped_flag
) continue;
2143 fprintf(fff
, "# Term %d\n", i
);
2146 * This doesn't seem to work under various WMs
2147 * since the decoration messes the position up
2149 * Hack -- Use saved window positions.
2150 * This means that we won't remember ingame repositioned
2151 * windows, but also means that WMs won't screw predefined
2152 * positions up. -CJN-
2155 /* Window specific location (x) */
2156 fprintf(fff
, "AT_X_%d=%d\n", i
, td
->win
->x_save
);
2158 /* Window specific location (y) */
2159 fprintf(fff
, "AT_Y_%d=%d\n", i
, td
->win
->y_save
);
2161 /* Window specific cols */
2162 fprintf(fff
, "COLS_%d=%d\n", i
, td
->t
.wid
);
2164 /* Window specific rows */
2165 fprintf(fff
, "ROWS_%d=%d\n", i
, td
->t
.hgt
);
2167 /* Window specific inner border offset (ox) */
2168 fprintf(fff
, "IBOX_%d=%d\n", i
, td
->win
->ox
);
2170 /* Window specific inner border offset (oy) */
2171 fprintf(fff
, "IBOY_%d=%d\n", i
, td
->win
->oy
);
2173 /* Window specific font name */
2174 fprintf(fff
, "FONT_%d=%s\n", i
, td
->fnt
->name
);
2176 /* Window specific tile width */
2177 fprintf(fff
, "TILE_WIDTH_%d=%d\n", i
, td
->tile_wid
);
2179 /* Window specific tile height */
2180 fprintf(fff
, "TILE_HEIGHT_%d=%d\n", i
, td
->tile_hgt
);
2187 (void)my_fclose(fff
);
2192 * Initialize a term_data
2194 static errr
term_data_init(term_data
*td
, int i
)
2198 cptr name
= angband_term_name
[i
];
2228 char font_name
[256];
2232 /* Get default font for this term */
2233 font
= get_default_font(i
);
2235 /* Build the filename */
2236 path_build(settings
, sizeof(settings
), ANGBAND_DIR_USER
, "x11-settings.prf");
2239 fff
= my_fopen(settings
, "r");
2244 /* Process the file */
2245 while (0 == my_fgets(fff
, buf
, sizeof(buf
)))
2250 /* Skip "empty" lines */
2251 if (!buf
[0]) continue;
2253 /* Skip "blank" lines */
2254 if (isspace((unsigned char)buf
[0])) continue;
2257 if (buf
[0] == '#') continue;
2259 /* Window specific location (x) */
2260 sprintf(cmd
, "AT_X_%d", i
);
2262 if (prefix(buf
, cmd
))
2264 str
= strstr(buf
, "=");
2265 x
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2269 /* Window specific location (y) */
2270 sprintf(cmd
, "AT_Y_%d", i
);
2272 if (prefix(buf
, cmd
))
2274 str
= strstr(buf
, "=");
2275 y
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2279 /* Window specific cols */
2280 sprintf(cmd
, "COLS_%d", i
);
2282 if (prefix(buf
, cmd
))
2284 str
= strstr(buf
, "=");
2285 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2286 if (val
> 0) cols
= val
;
2290 /* Window specific rows */
2291 sprintf(cmd
, "ROWS_%d", i
);
2293 if (prefix(buf
, cmd
))
2295 str
= strstr(buf
, "=");
2296 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2297 if (val
> 0) rows
= val
;
2301 /* Window specific inner border offset (ox) */
2302 sprintf(cmd
, "IBOX_%d", i
);
2304 if (prefix(buf
, cmd
))
2306 str
= strstr(buf
, "=");
2307 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2308 if (val
> 0) ox
= val
;
2312 /* Window specific inner border offset (oy) */
2313 sprintf(cmd
, "IBOY_%d", i
);
2315 if (prefix(buf
, cmd
))
2317 str
= strstr(buf
, "=");
2318 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2319 if (val
> 0) oy
= val
;
2323 /* Window specific font name */
2324 sprintf(cmd
, "FONT_%d", i
);
2326 if (prefix(buf
, cmd
))
2328 str
= strstr(buf
, "=");
2331 my_strcpy(font_name
, str
+ 1, sizeof(font_name
));
2337 /* Window specific tile width */
2338 sprintf(cmd
, "TILE_WIDTH_%d", i
);
2340 if (prefix(buf
, cmd
))
2342 str
= strstr(buf
, "=");
2343 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2344 if (val
> 0) td
->tile_wid
= val
;
2348 /* Window specific tile height */
2349 sprintf(cmd
, "TILE_HEIGHT_%d", i
);
2351 if (prefix(buf
, cmd
))
2353 str
= strstr(buf
, "=");
2354 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2355 if (val
> 0) td
->tile_hgt
= val
;
2365 * Env-vars overwrite the settings in the settings file
2368 /* Window specific location (x) */
2369 sprintf(buf
, "ANGBAND_X11_AT_X_%d", i
);
2371 val
= (str
!= NULL
) ? atoi(str
) : -1;
2372 if (val
> 0) x
= val
;
2374 /* Window specific location (y) */
2375 sprintf(buf
, "ANGBAND_X11_AT_Y_%d", i
);
2377 val
= (str
!= NULL
) ? atoi(str
) : -1;
2378 if (val
> 0) y
= val
;
2380 /* Window specific cols */
2381 sprintf(buf
, "ANGBAND_X11_COLS_%d", i
);
2383 val
= (str
!= NULL
) ? atoi(str
) : -1;
2384 if (val
> 0) cols
= val
;
2386 /* Window specific rows */
2387 sprintf(buf
, "ANGBAND_X11_ROWS_%d", i
);
2389 val
= (str
!= NULL
) ? atoi(str
) : -1;
2390 if (val
> 0) rows
= val
;
2392 /* Window specific inner border offset (ox) */
2393 sprintf(buf
, "ANGBAND_X11_IBOX_%d", i
);
2395 val
= (str
!= NULL
) ? atoi(str
) : -1;
2396 if (val
> 0) ox
= val
;
2398 /* Window specific inner border offset (oy) */
2399 sprintf(buf
, "ANGBAND_X11_IBOY_%d", i
);
2401 val
= (str
!= NULL
) ? atoi(str
) : -1;
2402 if (val
> 0) oy
= val
;
2404 /* Window specific font name */
2405 sprintf(buf
, "ANGBAND_X11_FONT_%d", i
);
2407 if (str
) font
= str
;
2409 /* Hack the main window must be at least 80x24 */
2412 if (cols
< 80) cols
= 80;
2413 if (rows
< 24) rows
= 24;
2416 /* Prepare the standard font */
2417 MAKE(td
->fnt
, infofnt
);
2418 Infofnt_set(td
->fnt
);
2419 if (Infofnt_init_data(font
)) quit_fmt("Couldn't load the requested font. (%s)", font
);
2421 /* Use proper tile size */
2422 if (td
->tile_wid
<= 0) td
->tile_wid
= td
->fnt
->twid
;
2423 if (td
->tile_hgt
<= 0) td
->tile_hgt
= td
->fnt
->hgt
;
2425 /* Allow bigtile mode */
2427 td
->tile_wid2
= td
->tile_wid
* 2;
2429 td
->tile_wid2
= td
->tile_wid
;
2431 /* Hack -- key buffer size */
2432 num
= ((i
== 0) ? 1024 : 16);
2434 /* Assume full size windows */
2435 wid
= cols
* td
->tile_wid
+ (ox
+ ox
);
2436 hgt
= rows
* td
->tile_hgt
+ (oy
+ oy
);
2438 /* Create a top-window */
2439 MAKE(td
->win
, infowin
);
2440 Infowin_set(td
->win
);
2441 Infowin_init_top(x
, y
, wid
, hgt
, 0,
2442 Metadpy
->fg
, Metadpy
->bg
);
2444 /* Ask for certain events */
2445 Infowin_set_mask(ExposureMask
| StructureNotifyMask
| KeyPressMask
2448 /* Set the window name */
2449 Infowin_set_name(name
);
2451 /* Save the inner border */
2455 /* Make Class Hints */
2456 ch
= XAllocClassHint();
2458 if (ch
== NULL
) quit("XAllocClassHint failed");
2460 my_strcpy(res_name
, name
, sizeof(res_name
));
2461 res_name
[0] = tolower((unsigned char)res_name
[0]);
2462 ch
->res_name
= res_name
;
2464 my_strcpy(res_class
, "Angband", sizeof(res_class
));
2465 ch
->res_class
= res_class
;
2467 XSetClassHint(Metadpy
->dpy
, Infowin
->win
, ch
);
2469 /* Make Size Hints */
2470 sh
= XAllocSizeHints();
2473 if (sh
== NULL
) quit("XAllocSizeHints failed");
2475 /* Main window has a differing minimum size */
2478 /* Main window min size is 80x24 */
2479 sh
->flags
= PMinSize
| PMaxSize
;
2480 sh
->min_width
= 80 * td
->tile_wid
+ (ox
+ ox
);
2481 sh
->min_height
= 24 * td
->tile_hgt
+ (oy
+ oy
);
2482 sh
->max_width
= 255 * td
->tile_wid
+ (ox
+ ox
);
2483 sh
->max_height
= 255 * td
->tile_hgt
+ (oy
+ oy
);
2486 /* Other windows can be shrunk to 1x1 */
2490 sh
->flags
= PMinSize
| PMaxSize
;
2491 sh
->min_width
= td
->tile_wid
+ (ox
+ ox
);
2492 sh
->min_height
= td
->tile_hgt
+ (oy
+ oy
);
2493 sh
->max_width
= 255 * td
->tile_wid
+ (ox
+ ox
);
2494 sh
->max_height
= 255 * td
->tile_hgt
+ (oy
+ oy
);
2497 /* Resize increment */
2498 sh
->flags
|= PResizeInc
;
2499 sh
->width_inc
= td
->tile_wid
;
2500 sh
->height_inc
= td
->tile_hgt
;
2502 /* Base window size */
2503 sh
->flags
|= PBaseSize
;
2504 sh
->base_width
= (ox
+ ox
);
2505 sh
->base_height
= (oy
+ oy
);
2507 /* Use the size hints */
2508 XSetWMNormalHints(Metadpy
->dpy
, Infowin
->win
, sh
);
2510 /* Map the window */
2513 /* Set pointers to allocated data */
2517 /* Move the window to requested location */
2518 if ((x
>= 0) && (y
>= 0)) Infowin_impell(x
, y
);
2521 /* Initialize the term */
2522 term_init(t
, cols
, rows
, num
);
2524 /* Use a "soft" cursor */
2525 t
->soft_cursor
= TRUE
;
2527 /* Erase with "white space" */
2528 t
->attr_blank
= TERM_WHITE
;
2529 t
->char_blank
= ' ';
2532 t
->xtra_hook
= Term_xtra_x11
;
2533 t
->curs_hook
= Term_curs_x11
;
2534 t
->bigcurs_hook
= Term_bigcurs_x11
;
2535 t
->wipe_hook
= Term_wipe_x11
;
2536 t
->text_hook
= Term_text_x11
;
2541 /* Activate (important) */
2549 const char help_x11
[] = "Basic X11, subopts -d<display> -n<windows>"
2552 "\n -b(Bigtile) -o(original) -a(AdamBolt) -g(David Gervais)"
2557 static void hook_quit(cptr str
)
2566 /* Free allocated data */
2567 for (i
= 0; i
< term_windows_open
; i
++)
2569 term_data
*td
= &data
[i
];
2572 /* Free size hints */
2575 /* Free class hints */
2579 Infofnt_set(td
->fnt
);
2580 (void)Infofnt_nuke();
2584 Infowin_set(td
->win
);
2585 (void)Infowin_nuke();
2594 (void)Infoclr_nuke();
2597 for (i
= 0; i
< MAX_COLORS
; ++i
)
2599 Infoclr_set(clr
[i
]);
2600 (void)Infoclr_nuke();
2604 /* Close link to display */
2605 (void)Metadpy_nuke();
2610 * Initialization function for an "X11" module to Angband
2612 errr
init_x11(int argc
, char **argv
)
2629 cptr bitmap_file
= NULL
;
2630 char filename
[1024];
2637 #endif /* USE_GRAPHICS */
2641 * Check x11-settings for the number of windows before handling
2642 * command line options to allow for easy override
2645 /* Build the filename */
2646 (void)path_build(settings
, sizeof(settings
), ANGBAND_DIR_USER
, "x11-settings.prf");
2649 fff
= my_fopen(settings
, "r");
2654 /* Process the file */
2655 while (0 == my_fgets(fff
, buf
, sizeof(buf
)))
2660 /* Skip "empty" lines */
2661 if (!buf
[0]) continue;
2663 /* Skip "blank" lines */
2664 if (isspace((unsigned char)buf
[0])) continue;
2667 if (buf
[0] == '#') continue;
2669 /* Number of terminal windows */
2670 if (prefix(buf
, "TERM_WINS"))
2672 str
= strstr(buf
, "=");
2673 val
= (str
!= NULL
) ? atoi(str
+ 1) : -1;
2674 if (val
> 0) num_term
= val
;
2680 (void)my_fclose(fff
);
2684 for (i
= 1; i
< argc
; i
++)
2686 if (prefix(argv
[i
], "-d"))
2688 dpy_name
= &argv
[i
][2];
2693 if (prefix(argv
[i
], "-s"))
2695 smoothRescaling
= FALSE
;
2699 if (prefix(argv
[i
], "-o"))
2701 arg_graphics
= GRAPHICS_ORIGINAL
;
2705 if (prefix(argv
[i
], "-a"))
2707 arg_graphics
= GRAPHICS_ADAM_BOLT
;
2711 if (prefix(argv
[i
], "-g"))
2713 smoothRescaling
= FALSE
;
2714 arg_graphics
= GRAPHICS_DAVID_GERVAIS
;
2718 if (prefix(argv
[i
], "-b"))
2724 #endif /* USE_GRAPHICS */
2726 if (prefix(argv
[i
], "-n"))
2728 num_term
= atoi(&argv
[i
][2]);
2729 if (num_term
> MAX_TERM_DATA
) num_term
= MAX_TERM_DATA
;
2730 else if (num_term
< 1) num_term
= 1;
2734 plog_fmt("Ignoring option: %s", argv
[i
]);
2738 /* Init the Metadpy if possible */
2739 if (Metadpy_init_name(dpy_name
)) return (-1);
2741 /* Remember the number of terminal windows */
2742 term_windows_open
= num_term
;
2744 /* Prepare cursor color */
2747 Infoclr_init_ppn(Metadpy
->fg
, Metadpy
->bg
, "xor", 0);
2750 /* Prepare normal colors */
2751 for (i
= 0; i
< 256; ++i
)
2755 MAKE(clr
[i
], infoclr
);
2757 Infoclr_set(clr
[i
]);
2759 /* Acquire Angband colors */
2760 color_table
[i
][0] = angband_color_table
[i
][0];
2761 color_table
[i
][1] = angband_color_table
[i
][1];
2762 color_table
[i
][2] = angband_color_table
[i
][2];
2763 color_table
[i
][3] = angband_color_table
[i
][3];
2765 /* Default to monochrome */
2766 pixel
= ((i
== 0) ? Metadpy
->bg
: Metadpy
->fg
);
2772 pixel
= create_pixel(Metadpy
->dpy
,
2778 /* Initialize the color */
2779 Infoclr_init_ppn(pixel
, Metadpy
->bg
, "cpy", 0);
2783 /* Initialize the windows */
2784 for (i
= 0; i
< num_term
; i
++)
2786 term_data
*td
= &data
[i
];
2788 /* Initialize the term_data */
2789 term_data_init(td
, i
);
2791 /* Save global entry */
2792 angband_term
[i
] = Term
;
2795 /* Raise the "Angband" window */
2796 Infowin_set(data
[0].win
);
2799 /* Activate the "Angband" window screen */
2800 Term_activate(&data
[0].t
);
2806 use_graphics
= GRAPHICS_NONE
;
2809 switch (arg_graphics
)
2811 case GRAPHICS_ADAM_BOLT
:
2813 bitmap_file
= "graf/16x16.bmp";
2815 use_graphics
= GRAPHICS_ADAM_BOLT
;
2816 use_transparency
= TRUE
;
2817 pict_wid
= pict_hgt
= 16;
2818 ANGBAND_GRAF
= "new";
2823 case GRAPHICS_ORIGINAL
:
2825 bitmap_file
= "graf/8x8.bmp";
2827 use_graphics
= GRAPHICS_ORIGINAL
;
2828 pict_wid
= pict_hgt
= 8;
2829 ANGBAND_GRAF
= "old";
2834 case GRAPHICS_DAVID_GERVAIS
:
2836 bitmap_file
= "graf/32x32.bmp";
2838 use_graphics
= GRAPHICS_DAVID_GERVAIS
;
2839 use_transparency
= TRUE
;
2840 pict_wid
= pict_hgt
= 32;
2841 ANGBAND_GRAF
= "david";
2851 path_build(filename
, sizeof(filename
), ANGBAND_DIR_XTRA
, bitmap_file
);
2852 if (!my_fexists(filename
))
2854 use_graphics
= GRAPHICS_NONE
;
2855 use_transparency
= FALSE
;
2862 if (use_graphics
!= GRAPHICS_NONE
)
2864 Display
*dpy
= Metadpy
->dpy
;
2869 for (i
= 0; i
< num_term
; i
++)
2871 term_data
*td
= &data
[i
];
2875 path_build(filename
, sizeof(filename
), ANGBAND_DIR_XTRA
, bitmap_file
);
2877 /* Load the graphical tiles */
2878 tiles_raw
= ReadBMP(dpy
, filename
);
2882 /* Initialize the windows */
2883 for (i
= 0; i
< num_term
; i
++)
2888 term_data
*td
= &data
[i
];
2889 term_data
*o_td
= NULL
;
2894 t
->pict_hook
= Term_pict_x11
;
2896 /* Use graphics sometimes */
2897 t
->higher_pict
= TRUE
;
2899 /* Look for another term with same tile size */
2900 for (j
= 0; j
< i
; j
++)
2904 if ((td
->tile_wid2
== o_td
->tile_wid2
) &&
2905 (td
->tile_hgt
== o_td
->tile_hgt
))
2915 td
->tiles
= ResizeImage(dpy
, tiles_raw
,
2917 td
->tile_wid2
, td
->tile_hgt
);
2921 /* Use same graphics */
2922 td
->tiles
= o_td
->tiles
;
2926 /* Free tiles_raw */
2930 /* Initialize the transparency masks */
2931 for (i
= 0; i
< num_term
; i
++)
2933 term_data
*td
= &data
[i
];
2935 int depth
= DefaultDepth(dpy
, DefaultScreen(dpy
));
2936 Visual
*visual
= DefaultVisual(dpy
, DefaultScreen(dpy
));
2940 /* Determine total bytes needed for image */
2942 jj
= (depth
- 1) >> 2;
2943 while (jj
>>= 1) ii
<<= 1;
2944 total
= td
->tile_wid2
* td
->tile_hgt
* ii
;
2947 TmpData
= (char *)malloc(total
);
2949 td
->TmpImage
= XCreateImage(dpy
, visual
, depth
,
2950 ZPixmap
, 0, TmpData
,
2951 td
->tile_wid2
, td
->tile_hgt
, 32, 0);
2955 #endif /* USE_GRAPHICS */
2958 quit_aux
= hook_quit
;
2964 #endif /* USE_X11 */