Angband 3.0.9b.
[angband.git] / src / main-x11.c
blobdc19dcc10fb08fc61b619a0d411ef11a84e8bdf4
1 /* File: main-x11.c */
3 /*
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.
9 */
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
24 * file simple.
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.
41 * #!/bin/csh
43 * # Describe attempt
44 * echo "Launching angband..."
45 * sleep 2
47 * # Main window
48 * setenv ANGBAND_X11_FONT_0 10x20
49 * setenv ANGBAND_X11_AT_X_0 5
50 * setenv ANGBAND_X11_AT_Y_0 510
52 * # Message window
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
58 * # Inventory window
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
64 * # Equipment window
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
85 * cd ~/Angband
87 * # Gamma correction
88 * setenv ANGBAND_X11_GAMMA 142
90 * # Launch Angband
91 * ./src/angband -mx11 -- -n6 &
97 #include "angband.h"
99 #define uint unsigned int
102 #ifdef USE_X11
104 #include "main.h"
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
127 * Notes on Colors:
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.
190 struct metadpy
192 Display *dpy;
193 Screen *screen;
194 Window root;
195 Colormap cmap;
197 char *name;
199 int fd;
201 uint width;
202 uint height;
203 uint depth;
205 Pixell black;
206 Pixell white;
208 Pixell bg;
209 Pixell fg;
210 Pixell zg;
212 uint mono:1;
213 uint color:1;
214 uint nuke:1;
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.
225 * - The Window
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
246 struct infowin
248 Window win;
249 long mask;
251 s16b ox, oy;
253 s16b x, y;
254 s16b x_save, y_save;
255 s16b w, h;
256 u16b b;
258 byte byte1;
260 uint mapped:1;
261 uint redraw:1;
262 uint resize:1;
264 uint nuke:1;
266 uint flag1:1;
267 uint flag2:1;
268 uint flag3:1;
269 uint flag4:1;
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.
289 struct infoclr
291 GC gc;
293 Pixell fg;
294 Pixell bg;
296 uint code:4;
297 uint stip:1;
298 uint nuke:1;
304 * A Structure to Hold Font Information
306 * - The 'XFontStruct*' (yields the 'Font')
308 * - The font name
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
319 struct infofnt
321 XFontStruct *info;
323 cptr name;
325 s16b wid;
326 s16b twid;
327 s16b hgt;
328 s16b asc;
330 byte off;
332 uint mono:1;
333 uint nuke:1;
339 * Forward declare
341 typedef struct term_data term_data;
344 * A structure for each "term"
346 struct term_data
348 term t;
350 infofnt *fnt;
352 infowin *win;
354 #ifdef USE_GRAPHICS
356 XImage *tiles;
358 /* Temporary storage for overlaying tiles. */
359 XImage *TmpImage;
361 int tile_wid;
362 int tile_wid2; /* Tile-width with bigscreen */
363 int tile_hgt;
365 #endif /* USE_GRAPHICS */
367 /* Pointers to allocated data, needed to clear up memory */
368 XClassHint *classh;
369 XSizeHints *sizeh;
375 /**** Generic Macros ****/
379 /* Set current metadpy (Metadpy) to 'M' */
380 #define Metadpy_set(M) \
381 Metadpy = 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)), \
400 X,Y,W,H,B,FG,BG)
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) \
415 (Infowin = (I))
418 /* Set the current Infoclr */
419 #define Infoclr_set(C) \
420 (Infoclr = (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) \
438 (Infofnt = (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);
470 * Actual color table
472 static infoclr *clr[MAX_COLORS];
476 /**** Generic code ****/
480 * Init the current metadpy, with various initialization stuff.
482 * Inputs:
483 * dpy: The Display* to use (if NULL, create it)
484 * name: The name of the Display (if NULL, the current)
486 * Notes:
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 */
500 if (!dpy)
502 /* Attempt to open the display */
503 dpy = XOpenDisplay(name);
505 /* Failure */
506 if (!dpy) return (-1);
508 /* We will have to nuke it when done */
509 m->nuke = 1;
512 /* Since the Display was given, use it */
513 else
515 /* We will not have to nuke it when done */
516 m->nuke = 0;
520 /*** Save some information ***/
522 /* Save the Display itself */
523 m->dpy = dpy;
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);
535 /* Extract the fd */
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 */
550 m->bg = m->black;
551 m->fg = m->white;
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" */
561 return (0);
566 * Nuke the current metadpy
568 static errr Metadpy_nuke(void)
570 metadpy *m = Metadpy;
573 /* If required, Free the Display */
574 if (m->nuke)
576 /* Close the Display */
577 XCloseDisplay(m->dpy);
579 /* Forget the Display */
580 m->dpy = (Display*)(NULL);
582 /* Do not nuke it again */
583 m->nuke = 0;
586 /* Return Success */
587 return (0);
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);
602 /* Success */
603 return (0);
608 * Make a simple beep
610 static errr Metadpy_do_beep(void)
612 /* Make a simple beep */
613 XBell(Metadpy->dpy, 100);
615 return (0);
621 * Set the name (in the title bar) of Infowin
623 static errr Infowin_set_name(cptr name)
625 Status st;
626 XTextProperty tp;
627 char buf[128];
628 char *bp = buf;
629 my_strcpy(buf, name, sizeof(buf));
630 st = XStringListToTextProperty(&bp, 1, &tp);
631 if (st) XSetWMName(Metadpy->dpy, Infowin->win, &tp);
632 return (0);
636 #ifndef IGNORE_UNUSED_FUNCTIONS
639 * Set the icon name of Infowin
641 static errr Infowin_set_icon_name(cptr name)
643 Status st;
644 XTextProperty tp;
645 char buf[128];
646 char *bp = buf;
647 my_strcpy(buf, name, sizeof(buf));
648 st = XStringListToTextProperty(&bp, 1, &tp);
649 if (st) XSetWMIconName(Metadpy->dpy, Infowin->win, &tp);
650 return (0);
653 #endif /* IGNORE_UNUSED_FUNCTIONS */
657 * Nuke Infowin
659 static errr Infowin_nuke(void)
661 infowin *iwin = Infowin;
663 /* Nuke if requested */
664 if (iwin->nuke)
666 /* Destory the old window */
667 XDestroyWindow(Metadpy->dpy, iwin->win);
670 /* Success */
671 return (0);
676 * Prepare a new 'infowin'.
678 static errr Infowin_prepare(Window xid)
680 infowin *iwin = Infowin;
682 Window tmp_win;
683 XWindowAttributes xwa;
684 int x, y;
685 unsigned int w, h, b, d;
687 /* Assign stuff */
688 iwin->win = xid;
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 */
694 iwin->x = x;
695 iwin->y = y;
696 iwin->x_save = x;
697 iwin->y_save = y;
698 iwin->w = w;
699 iwin->h = h;
700 iwin->b = b;
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 */
710 iwin->redraw = 1;
712 /* Success */
713 return (0);
717 #ifndef IGNORE_UNUSED_FUNCTIONS
720 * Initialize a new 'infowin'.
722 static errr Infowin_init_real(Window xid)
724 /* Wipe it clean */
725 (void)WIPE(Infowin, infowin);
727 /* Start out non-nukable */
728 Infowin->nuke = 0;
730 /* Attempt to Prepare ourself */
731 return (Infowin_prepare(xid));
734 #endif /* IGNORE_UNUSED_FUNCTIONS */
738 * Init an infowin by giving some data.
740 * Inputs:
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
746 * Notes:
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)
752 Window xid;
754 /* Wipe it clean */
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 */
766 if (dad == None)
768 /* #ifdef USE_GRAPHICS
770 xid = XCreateWindow(Metadpy->dpy, Metadpy->root, x, y, w, h, b, 8, InputOutput, CopyFromParent, 0, 0);
772 else
775 /* #else */
777 dad = Metadpy->root;
779 /* #endif */
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 */
791 Infowin->nuke = 1;
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);
810 /* Success */
811 return (0);
816 * Request that Infowin be mapped
818 static errr Infowin_map(void)
820 /* Execute the Mapping */
821 XMapWindow(Metadpy->dpy, Infowin->win);
823 /* Success */
824 return (0);
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);
838 /* Success */
839 return (0);
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);
853 /* Success */
854 return (0);
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);
868 /* Success */
869 return (0);
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);
883 /* Success */
884 return (0);
889 * Resize an infowin
891 static errr Infowin_resize(int w, int h)
893 /* Execute the request */
894 XResizeWindow(Metadpy->dpy, Infowin->win, w, h);
896 /* Success */
897 return (0);
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);
911 /* Success */
912 return (0);
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);
926 /* Success */
927 return (0);
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);
942 /* Success */
943 return (0);
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[] =
957 "cpy", "3",
958 "xor", "6",
959 "and", "1",
960 "ior", "7",
961 "nor", "8",
962 "inv", "10",
963 "clr", "0",
964 "set", "15",
966 "src", "3",
967 "dst", "5",
969 "+andReverse", "2",
970 "+andInverted", "4",
971 "+noop", "5",
972 "+equiv", "9",
973 "+orReverse", "11",
974 "+copyInverted", "12",
975 "+orInverted", "13",
976 "+nand", "14",
977 NULL
982 * Parse a word into an operation "code"
984 * Inputs:
985 * str: A string, hopefully representing an Operation
987 * Output:
988 * 0-15: if 'str' is a valid Operation
989 * -1: if 'str' could not be parsed
991 static int Infoclr_Opcode(cptr str)
993 register int i;
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 */
1007 return (-1);
1011 #ifndef IGNORE_UNUSED_FUNCTIONS
1014 * Request a Pixell by name. Note: uses 'Metadpy'.
1016 * Inputs:
1017 * name: The name of the color to try to load (see below)
1019 * Output:
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)
1028 XColor scrn;
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);
1082 /* Assign the GC */
1083 iclr->gc = gc;
1085 /* Success */
1086 return (0);
1089 #endif /* IGNORE_UNUSED_FUNCTIONS */
1093 * Nuke an old 'infoclr'.
1095 static errr Infoclr_nuke(void)
1097 infoclr *iclr = Infoclr;
1099 /* Deal with 'GC' */
1100 if (iclr->nuke)
1102 /* Free the GC */
1103 XFreeGC(Metadpy->dpy, iclr->gc);
1106 /* Forget the current */
1107 Infoclr = (infoclr*)(NULL);
1109 /* Success */
1110 return (0);
1115 * Initialize an infoclr with some data
1117 * Inputs:
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;
1127 GC gc;
1128 XGCValues gcv;
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 */
1146 gcv.function = op;
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);
1177 /* Assign the GC */
1178 iclr->gc = gc;
1180 /* Nuke it when done */
1181 iclr->nuke = 1;
1183 /* Assign the parms */
1184 iclr->fg = fg;
1185 iclr->bg = bg;
1186 iclr->code = op;
1187 iclr->stip = stip ? 1 : 0;
1189 /* Success */
1190 return (0);
1196 * Change the 'fg' for an infoclr
1198 * Inputs:
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);
1212 /*** Change ***/
1214 /* Change */
1215 XSetForeground(Metadpy->dpy, iclr->gc, fg);
1217 /* Success */
1218 return (0);
1224 * Nuke an old 'infofnt'.
1226 static errr Infofnt_nuke(void)
1228 infofnt *ifnt = Infofnt;
1230 /* Deal with 'name' */
1231 if (ifnt->name)
1233 /* Free the name */
1234 string_free(ifnt->name);
1237 /* Nuke info if needed */
1238 if (ifnt->nuke)
1240 /* Free the font */
1241 XFreeFont(Metadpy->dpy, ifnt->info);
1244 /* Success */
1245 return (0);
1250 * Prepare a new 'infofnt'
1252 static errr Infofnt_prepare(XFontStruct *info)
1254 infofnt *ifnt = Infofnt;
1256 XCharStruct *cs;
1258 /* Assign the struct */
1259 ifnt->info = info;
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;
1270 /* Success */
1271 return (0);
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);
1285 /* No nuking */
1286 Infofnt->nuke = 0;
1288 /* Attempt to prepare it */
1289 return (Infofnt_prepare(info));
1292 #endif /* IGNORE_UNUSED_FUNCTIONS */
1296 * Init an infofnt by its Name
1298 * Inputs:
1299 * name: The name of the requested Font
1301 static errr Infofnt_init_data(cptr name)
1303 XFontStruct *info;
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))
1326 /* Free the font */
1327 XFreeFont(Metadpy->dpy, info);
1329 /* Fail */
1330 return (-1);
1333 /* Save a copy of the font name */
1334 Infofnt->name = string_make(name);
1336 /* Mark it as nukable */
1337 Infofnt->nuke = 1;
1339 /* HACK - force all fonts to be printed character by character */
1340 Infofnt->mono = 1;
1342 /* Success */
1343 return (0);
1348 * Standard Text
1350 static errr Infofnt_text_std(int x, int y, cptr str, int len)
1352 int i;
1353 int w, h;
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 */
1383 h = td->tile_hgt;
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);
1395 y += Infofnt->asc;
1398 /*** Handle the fake mono we can enforce on fonts ***/
1400 /* Monotize the font */
1401 if (Infofnt->mono)
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 */
1413 else
1415 /* Note that the Infoclr is set up to contain the Infofnt */
1416 XDrawImageString(Metadpy->dpy, Infowin->win, Infoclr->gc,
1417 x, y, str, len);
1420 /* Success */
1421 return (0);
1426 * Painting where text would be
1428 static errr Infofnt_text_non(int x, int y, cptr str, int len)
1430 int w, h;
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 */
1452 h = td->tile_hgt;
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);
1463 /* Success */
1464 return (0);
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;
1523 uint ks1;
1525 KeySym ks;
1527 char buf[128];
1528 char msg[128];
1531 /* Check for "normal" keypresses */
1532 n = XLookupString(ev, buf, 125, &ks, NULL);
1534 /* Terminate */
1535 buf[n] = '\0';
1538 /* Hack -- Ignore "modifier keys" */
1539 if (IsModifierKey(ks)) return;
1542 /* Hack -- convert into an unsigned int */
1543 ks1 = (uint)(ks);
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]);
1558 /* All done */
1559 return;
1563 /* Handle a few standard keys (bypass modifiers) XXX XXX XXX */
1564 switch (ks1)
1566 case XK_Escape:
1568 Term_keypress(ESCAPE);
1569 return;
1572 case XK_Return:
1574 Term_keypress('\r');
1575 return;
1578 case XK_Tab:
1580 Term_keypress('\t');
1581 return;
1584 case XK_Delete:
1585 case XK_BackSpace:
1587 Term_keypress('\010');
1588 return;
1593 /* Hack -- Use the KeySym */
1594 if (ks)
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 */
1603 else
1605 strnfmt(msg, sizeof(msg), "%c%s%s%s%sK_%X%c", 31,
1606 mc ? "N" : "", ms ? "S" : "",
1607 mo ? "O" : "", mx ? "M" : "",
1608 ev->keycode, 13);
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;
1640 * Process events
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;
1651 int i, x, y;
1652 int window = 0;
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);
1665 return 0;
1669 /* Scan the windows */
1670 for (i = 0; i < MAX_TERM_DATA; i++)
1672 if (xev->xany.window == data[i].win->win)
1674 td = &data[i];
1675 iwin = td->win;
1676 window = i;
1677 break;
1681 /* Unknown window */
1682 if (!td || !iwin) return (0);
1685 /* Hack -- activate the Term */
1686 Term_activate(&td->t);
1688 /* Hack -- activate the window */
1689 Infowin_set(iwin);
1692 /* Switch on the Type */
1693 switch (xev->type)
1695 case ButtonPress:
1697 bool press = (xev->type == ButtonPress);
1699 int z = 0;
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;
1711 else z = 0;
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);
1717 break;
1720 #if 0
1721 case MotionNotify:
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);
1731 break;
1733 #endif
1735 case KeyPress:
1737 /* Save the mouse location */
1738 x = xev->xkey.x;
1739 y = xev->xkey.y;
1741 /* Hack -- use "old" term */
1742 Term_activate(&old_td->t);
1744 /* Process the key */
1745 react_keypress(&(xev->xkey));
1747 break;
1750 case Expose:
1752 int x1, x2, y1, y2;
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);
1762 break;
1765 case MapNotify:
1767 Infowin->mapped = 1;
1768 Term->mapped_flag = TRUE;
1769 break;
1772 case UnmapNotify:
1774 Infowin->mapped = 0;
1775 Term->mapped_flag = FALSE;
1776 break;
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;
1801 if (window == 0)
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))
1818 /* Resize window */
1819 Infowin_set(td->win);
1820 Infowin_resize(wid, hgt);
1823 break;
1828 /* Hack -- Activate the old term */
1829 Term_activate(&old_td->t);
1831 /* Hack -- Activate the proper window */
1832 Infowin_set(old_td->win);
1835 /* Success */
1836 return (0);
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" */
1848 if (v)
1850 /* Activate the window */
1851 Infowin_set(td->win);
1853 /* Activate the font */
1854 Infofnt_set(td->fnt);
1857 /* Success */
1858 return (0);
1863 * React to changes
1865 static errr Term_xtra_x11_react(void)
1867 int i;
1869 if (Metadpy->color)
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]))
1879 Pixell pixel;
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];
1887 /* Create pixel */
1888 pixel = create_pixel(Metadpy->dpy,
1889 color_table[i][1],
1890 color_table[i][2],
1891 color_table[i][3]);
1893 /* Change the foreground */
1894 Infoclr_set(clr[i]);
1895 Infoclr_change_fg(pixel);
1900 /* Success */
1901 return (0);
1906 * Handle a "special request"
1908 static errr Term_xtra_x11(int n, int v)
1910 /* Handle a subset of the legal requests */
1911 switch (n)
1913 /* Make a noise */
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);
1937 return (0);
1939 /* React to changes */
1940 case TERM_XTRA_REACT: return (Term_xtra_x11_react());
1943 /* Unknown */
1944 return (1);
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);
1960 /* Success */
1961 return (0);
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);
1977 /* Success */
1978 return (0);
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);
1993 /* Success */
1994 return (0);
1999 * Draw some textual characters.
2001 static errr Term_text_x11(int x, int y, int n, byte a, cptr s)
2003 /* Draw the text */
2004 Infoclr_set(clr[a]);
2006 /* Draw the text */
2007 Infofnt_text_std(x, y, s, n);
2009 /* Success */
2010 return (0);
2014 #ifdef USE_GRAPHICS
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)
2021 int i;
2022 int x1 = 0, y1 = 0;
2024 byte a;
2025 char c;
2027 byte ta;
2028 char tc;
2030 int x2, y2;
2031 int k,l;
2033 unsigned long pixel, blank;
2035 term_data *td = (term_data*)(Term->data);
2037 y *= td->tile_hgt;
2038 x *= td->tile_wid;
2040 /* Add in affect of window boundaries */
2041 y += Infowin->oy;
2042 x += Infowin->ox;
2044 for (i = 0; i < n; ++i)
2046 a = *ap++;
2047 c = *cp++;
2049 ta = *tap++;
2050 tc = *tcp++;
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,
2066 clr[0]->gc,
2067 td->tiles,
2068 x1, y1,
2069 x, y,
2070 td->tile_wid2, td->tile_hgt);
2072 else
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);
2077 else
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);
2090 if (pixel == blank)
2091 pixel = 0L;
2094 /* Store into the temp storage. */
2095 XPutPixel(td->TmpImage, k, l, pixel);
2100 /* Draw to screen */
2101 XPutImage(Metadpy->dpy, td->win->win,
2102 clr[0]->gc,
2103 td->TmpImage,
2104 0, 0, x, y,
2105 td->tile_wid2, td->tile_hgt);
2108 x += td->tile_wid;
2111 /* Success */
2112 return (0);
2115 #endif /* USE_GRAPHICS */
2118 static void save_prefs(void)
2120 FILE *fff;
2121 int i;
2123 /* Open the settings file */
2124 fff = my_fopen(settings, "w");
2126 /* Oops */
2127 if (!fff) return;
2129 /* Header */
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;
2142 /* Header */
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);
2182 /* Footer */
2183 fprintf(fff, "\n");
2186 /* Close */
2187 (void)my_fclose(fff);
2192 * Initialize a term_data
2194 static errr term_data_init(term_data *td, int i)
2196 term *t = &td->t;
2198 cptr name = angband_term_name[i];
2200 cptr font;
2202 int x = 0;
2203 int y = 0;
2205 int cols = 80;
2206 int rows = 24;
2208 int ox = 1;
2209 int oy = 1;
2211 int wid, hgt, num;
2213 cptr str;
2215 int val;
2217 XClassHint *ch;
2219 char res_name[20];
2220 char res_class[20];
2222 XSizeHints *sh;
2224 FILE *fff;
2226 char buf[1024];
2227 char cmd[40];
2228 char font_name[256];
2230 int line = 0;
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");
2238 /* Open the file */
2239 fff = my_fopen(settings, "r");
2241 /* File exists */
2242 if (fff)
2244 /* Process the file */
2245 while (0 == my_fgets(fff, buf, sizeof(buf)))
2247 /* Count lines */
2248 line++;
2250 /* Skip "empty" lines */
2251 if (!buf[0]) continue;
2253 /* Skip "blank" lines */
2254 if (isspace((unsigned char)buf[0])) continue;
2256 /* Skip comments */
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;
2266 continue;
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;
2276 continue;
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;
2287 continue;
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;
2298 continue;
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;
2309 continue;
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;
2320 continue;
2323 /* Window specific font name */
2324 sprintf(cmd, "FONT_%d", i);
2326 if (prefix(buf, cmd))
2328 str = strstr(buf, "=");
2329 if (str != NULL)
2331 my_strcpy(font_name, str + 1, sizeof(font_name));
2332 font = font_name;
2334 continue;
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;
2345 continue;
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;
2356 continue;
2360 /* Close */
2361 my_fclose(fff);
2365 * Env-vars overwrite the settings in the settings file
2368 /* Window specific location (x) */
2369 sprintf(buf, "ANGBAND_X11_AT_X_%d", i);
2370 str = getenv(buf);
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);
2376 str = getenv(buf);
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);
2382 str = getenv(buf);
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);
2388 str = getenv(buf);
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);
2394 str = getenv(buf);
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);
2400 str = getenv(buf);
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);
2406 str = getenv(buf);
2407 if (str) font = str;
2409 /* Hack the main window must be at least 80x24 */
2410 if (!i)
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 */
2426 if (use_bigtile)
2427 td->tile_wid2 = td->tile_wid * 2;
2428 else
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
2446 | ButtonPressMask);
2448 /* Set the window name */
2449 Infowin_set_name(name);
2451 /* Save the inner border */
2452 Infowin->ox = ox;
2453 Infowin->oy = oy;
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();
2472 /* Oops */
2473 if (sh == NULL) quit("XAllocSizeHints failed");
2475 /* Main window has a differing minimum size */
2476 if (i == 0)
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 */
2487 else
2489 /* Other windows */
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 */
2511 Infowin_map();
2513 /* Set pointers to allocated data */
2514 td->sizeh = sh;
2515 td->classh = ch;
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 = ' ';
2531 /* Hooks */
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;
2538 /* Save the data */
2539 t->data = td;
2541 /* Activate (important) */
2542 Term_activate(t);
2544 /* Success */
2545 return (0);
2549 const char help_x11[] = "Basic X11, subopts -d<display> -n<windows>"
2550 #ifdef USE_GRAPHICS
2551 " -s(moothRescale)"
2552 "\n -b(Bigtile) -o(original) -a(AdamBolt) -g(David Gervais)"
2553 #endif
2557 static void hook_quit(cptr str)
2559 int i;
2561 /* Unused */
2562 (void)str;
2564 save_prefs();
2566 /* Free allocated data */
2567 for (i = 0; i < term_windows_open; i++)
2569 term_data *td = &data[i];
2570 term *t = &td->t;
2572 /* Free size hints */
2573 XFree(td->sizeh);
2575 /* Free class hints */
2576 XFree(td->classh);
2578 /* Free fonts */
2579 Infofnt_set(td->fnt);
2580 (void)Infofnt_nuke();
2581 KILL(td->fnt);
2583 /* Free window */
2584 Infowin_set(td->win);
2585 (void)Infowin_nuke();
2586 KILL(td->win);
2588 /* Free term */
2589 (void)term_nuke(t);
2592 /* Free colors */
2593 Infoclr_set(xor);
2594 (void)Infoclr_nuke();
2595 KILL(xor);
2597 for (i = 0; i < MAX_COLORS; ++i)
2599 Infoclr_set(clr[i]);
2600 (void)Infoclr_nuke();
2601 KILL(clr[i]);
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)
2614 int i;
2616 cptr dpy_name = "";
2618 int num_term = 1;
2620 FILE *fff;
2622 char buf[1024];
2623 cptr str;
2624 int val;
2625 int line = 0;
2627 #ifdef USE_GRAPHICS
2629 cptr bitmap_file = NULL;
2630 char filename[1024];
2632 int pict_wid = 0;
2633 int pict_hgt = 0;
2635 char *TmpData;
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");
2648 /* Open the file */
2649 fff = my_fopen(settings, "r");
2651 /* File exists */
2652 if (fff)
2654 /* Process the file */
2655 while (0 == my_fgets(fff, buf, sizeof(buf)))
2657 /* Count lines */
2658 line++;
2660 /* Skip "empty" lines */
2661 if (!buf[0]) continue;
2663 /* Skip "blank" lines */
2664 if (isspace((unsigned char)buf[0])) continue;
2666 /* Skip comments */
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;
2675 continue;
2679 /* Close */
2680 (void)my_fclose(fff);
2683 /* Parse args */
2684 for (i = 1; i < argc; i++)
2686 if (prefix(argv[i], "-d"))
2688 dpy_name = &argv[i][2];
2689 continue;
2692 #ifdef USE_GRAPHICS
2693 if (prefix(argv[i], "-s"))
2695 smoothRescaling = FALSE;
2696 continue;
2699 if (prefix(argv[i], "-o"))
2701 arg_graphics = GRAPHICS_ORIGINAL;
2702 continue;
2705 if (prefix(argv[i], "-a"))
2707 arg_graphics = GRAPHICS_ADAM_BOLT;
2708 continue;
2711 if (prefix(argv[i], "-g"))
2713 smoothRescaling = FALSE;
2714 arg_graphics = GRAPHICS_DAVID_GERVAIS;
2715 continue;
2718 if (prefix(argv[i], "-b"))
2720 use_bigtile = TRUE;
2721 continue;
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;
2731 continue;
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 */
2745 MAKE(xor, infoclr);
2746 Infoclr_set(xor);
2747 Infoclr_init_ppn(Metadpy->fg, Metadpy->bg, "xor", 0);
2750 /* Prepare normal colors */
2751 for (i = 0; i < 256; ++i)
2753 Pixell pixel;
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);
2768 /* Handle color */
2769 if (Metadpy->color)
2771 /* Create pixel */
2772 pixel = create_pixel(Metadpy->dpy,
2773 color_table[i][1],
2774 color_table[i][2],
2775 color_table[i][3]);
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);
2797 Infowin_raise();
2799 /* Activate the "Angband" window screen */
2800 Term_activate(&data[0].t);
2803 #ifdef USE_GRAPHICS
2805 /* Paranoia */
2806 use_graphics = GRAPHICS_NONE;
2808 /* Try graphics */
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";
2820 break;
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";
2831 break;
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";
2843 break;
2848 if (bitmap_file)
2850 /* Try the file */
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;
2856 ANGBAND_GRAF = 0;
2861 /* Load graphics */
2862 if (use_graphics != GRAPHICS_NONE)
2864 Display *dpy = Metadpy->dpy;
2866 XImage *tiles_raw;
2868 /* Initialize */
2869 for (i = 0; i < num_term; i++)
2871 term_data *td = &data[i];
2872 td->tiles = NULL;
2875 path_build(filename, sizeof(filename), ANGBAND_DIR_XTRA, bitmap_file);
2877 /* Load the graphical tiles */
2878 tiles_raw = ReadBMP(dpy, filename);
2880 if (tiles_raw)
2882 /* Initialize the windows */
2883 for (i = 0; i < num_term; i++)
2885 int j;
2886 bool same = FALSE;
2888 term_data *td = &data[i];
2889 term_data *o_td = NULL;
2891 term *t = &td->t;
2893 /* Graphics hook */
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++)
2902 o_td = &data[j];
2904 if ((td->tile_wid2 == o_td->tile_wid2) &&
2905 (td->tile_hgt == o_td->tile_hgt))
2907 same = TRUE;
2908 break;
2912 if (!same)
2914 /* Resize tiles */
2915 td->tiles = ResizeImage(dpy, tiles_raw,
2916 pict_wid, pict_hgt,
2917 td->tile_wid2, td->tile_hgt);
2919 else
2921 /* Use same graphics */
2922 td->tiles = o_td->tiles;
2926 /* Free tiles_raw */
2927 FREE(tiles_raw);
2930 /* Initialize the transparency masks */
2931 for (i = 0; i < num_term; i++)
2933 term_data *td = &data[i];
2934 int ii, jj;
2935 int depth = DefaultDepth(dpy, DefaultScreen(dpy));
2936 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
2937 int total;
2940 /* Determine total bytes needed for image */
2941 ii = 1;
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 */
2957 /* Activate hook */
2958 quit_aux = hook_quit;
2960 /* Success */
2961 return (0);
2964 #endif /* USE_X11 */