1 /* File: main-xaw.c */
3 /* Purpose: Support for X Athena Widget based Angband */
4 /* Most code written by Torbj
\vn Lindgren (tl@cd.chalmers.se) */
8 #include "game-option/runtime-arguments.h"
9 #include "system/angband.h"
10 #include "util/int-char-converter.h"
12 #ifndef __MAKEDEPEND__
13 #include <X11/CoreP.h>
14 #include <X11/Intrinsic.h>
15 #include <X11/IntrinsicP.h>
16 #include <X11/Shell.h>
17 #include <X11/ShellP.h>
18 #include <X11/StringDefs.h>
19 #include <X11/Xaw/Simple.h>
20 #include <X11/Xaw/SimpleP.h>
21 #include <X11/Xaw/XawInit.h>
23 #include <X11/Xutil.h>
24 #include <X11/keysym.h>
25 #include <X11/keysymdef.h>
26 #endif /* __MAKEDEPEND__ */
28 /*****************************************************
30 * Resource description
32 *****************************************************/
36 Name Class RepType Default Value
37 ---- ----- ------- -------------
38 background Background Pixel XtDefaultBackground
39 border BorderColor Pixel XtDefaultForeground
40 borderWidth BorderWidth Dimension 1
41 cursor Cursor Cursor None
42 cursorName Cursor String nullptr
43 destroyCallback Callback Pointer nullptr
44 height Height Dimension 0
45 insensitiveBorder Insensitive Pixmap Gray
46 mappedWhenManaged MappedWhenManaged Boolean True
47 pointerColor Foreground Pixel XtDefaultForeground
48 pointerColorBackground Background Pixel XtDefaultBackground
49 sensitive Sensitive Boolean True
50 width Width Dimension 0
58 My own X Resources look like this (on a 1152x900 screen):
60 angband*angband*font: 12x24
61 angband*angband*geometry: +0+-20
62 angband*recall*font: 7x13
63 angband*recall*geometry: 80x10+0+586
64 angband*choice*font: 7x13
65 angband*choice*geometry: -0-0
67 It's also possible to change the colors using X Resources, the
68 standard colors would look like:
70 angband*color0: #000000
71 angband*color1: #ffffff
72 angband*color2: #a6a6a6
73 angband*color3: #ff6302
74 angband*color4: #ca0808
75 angband*color5: #008e18
76 angband*color6: #0000e3
77 angband*color7: #814007
78 angband*color8: #6b6b6b
79 angband*color9: #d6d6d6
80 angband*color10: #5100c2
81 angband*color11: #fdf105
82 angband*color12: #ff9259
83 angband*color13: #26cf17
84 angband*color14: #02b2f2
85 angband*color15: #b28b48
87 And the newer colors look like:
89 angband*color0: #000000
90 angband*color1: #ffffff
91 angband*color2: #d7d7d7
92 angband*color3: #ff9200
93 angband*color4: #ff0000
94 angband*color5: #00cd00
95 angband*color6: #0000fe
96 angband*color7: #c86400
97 angband*color8: #a3a3a3
98 angband*color9: #ebebeb
99 angband*color10: #a500ff
100 angband*color11: #fffd00
101 angband*color12: #ff00bc
102 angband*color13: #00ff00
103 angband*color14: #00c8ff
104 angband*color15: #ffcc80
106 Some older monochrome monitors have problem with white text on black
107 background. The new code can handle the reverse situation if the user
110 The following X Resources gives black text on white background using
111 Angband/Xaw. The other colors (2-15) isn't changed, since they're not
112 used on a monochrome monitor.
114 angband*color0: #ffffff
115 angband*color1: #000000
119 /* New resource names */
120 #define XtNstartRows "startRows"
121 #define XtNstartColumns "startColumns"
122 #define XtNminRows "minRows"
123 #define XtNminColumns "minColumns"
124 #define XtNmaxRows "maxRows"
125 #define XtNmaxColumns "maxColumns"
126 #define XtNinternalBorder "internalBorder"
127 #define XtNcolor0 "color0"
128 #define XtNcolor1 "color1"
129 #define XtNcolor2 "color2"
130 #define XtNcolor3 "color3"
131 #define XtNcolor4 "color4"
132 #define XtNcolor5 "color5"
133 #define XtNcolor6 "color6"
134 #define XtNcolor7 "color7"
135 #define XtNcolor8 "color8"
136 #define XtNcolor9 "color9"
137 #define XtNcolor10 "color10"
138 #define XtNcolor11 "color11"
139 #define XtNcolor12 "color12"
140 #define XtNcolor13 "color13"
141 #define XtNcolor14 "color14"
142 #define XtNcolor15 "color15"
143 #define XtNredrawCallback "redrawCallback"
145 /* External definitions */
147 #define NUM_COLORS 16
149 /* C Widget type definition */
151 typedef struct AngbandRec *AngbandWidget;
153 /* C Widget class type definition */
155 typedef struct AngbandClassRec *AngbandWidgetClass;
158 * New fields for the Angband widget record
162 /* Settable resources */
171 Pixel color[NUM_COLORS];
172 XtCallbackList redraw_callbacks;
176 Dimension fontheight;
178 Dimension fontascent;
179 GC gc[NUM_COLORS + 1]; /* Includes a special 'xor' color */
183 * Full instance record declaration
192 * New fields for the Angband widget class record
194 struct AngbandClassPart {
199 * Full class record declaration
201 struct AngbandClassRec {
202 CoreClassPart core_class;
203 SimpleClassPart simple_class;
204 AngbandClassPart angband_class;
207 /* Angband widget, Created by Torbj
\vn Lindgren (tl@cd.chalmers.se) */
210 * Note that it isn't as self-contained as it really should be,
211 * originally everything was output to a Pixmap which was later copied
212 * to the screen when necessary. I had to abandon that idea since
213 * Pixmaps creates big performance problems for some really old X
214 * terminals (such as 3/50's running Xkernel).
218 * The default colors used is based on the ones used in main-mac.c.
219 * The main difference is that they are gamma corrected for a gamma of
220 * 1.6. MacOS do gamma correction afterwards, but X uses raw
221 * colors. The Gamma of most color screens are about 1.5 - 1.7.
222 * Color 12 was later changed a bit so that it didn't look as similar
226 #define offset(field) XtOffsetOf(AngbandRec, angband.field)
229 * Fallback resources for Angband widget
231 static XtResource resources[] = { { XtNstartRows, XtCValue, XtRInt, sizeof(int), offset(start_rows), XtRImmediate, (XtPointer)24 },
232 { XtNstartColumns, XtCValue, XtRInt, sizeof(int), offset(start_columns), XtRImmediate, (XtPointer)80 },
233 { XtNminRows, XtCValue, XtRInt, sizeof(int), offset(min_rows), XtRImmediate, (XtPointer)1 },
234 { XtNminColumns, XtCValue, XtRInt, sizeof(int), offset(min_columns), XtRImmediate, (XtPointer)1 },
235 { XtNmaxRows, XtCValue, XtRInt, sizeof(int), offset(max_rows), XtRImmediate, (XtPointer)24 },
236 { XtNmaxColumns, XtCValue, XtRInt, sizeof(int), offset(max_columns), XtRImmediate, (XtPointer)80 },
237 { XtNinternalBorder, XtCValue, XtRInt, sizeof(int), offset(internal_border), XtRImmediate, (XtPointer)2 },
238 { XtNfont, XtCFont, XtRString, sizeof(char *), offset(font), XtRString, "9x15" },
239 { XtNcolor0, XtCColor, XtRPixel, sizeof(Pixel), offset(color[0]), XtRString, "black" },
240 { XtNcolor1, XtCColor, XtRPixel, sizeof(Pixel), offset(color[1]), XtRString, "white" },
241 { XtNcolor2, XtCColor, XtRPixel, sizeof(Pixel), offset(color[2]), XtRString, "#d7d7d7" },
242 { XtNcolor3, XtCColor, XtRPixel, sizeof(Pixel), offset(color[3]), XtRString, "#ff9200" },
243 { XtNcolor4, XtCColor, XtRPixel, sizeof(Pixel), offset(color[4]), XtRString, "#ff0000" },
244 { XtNcolor5, XtCColor, XtRPixel, sizeof(Pixel), offset(color[5]), XtRString, "#00cd00" },
245 { XtNcolor6, XtCColor, XtRPixel, sizeof(Pixel), offset(color[6]), XtRString, "#0000fe" },
246 { XtNcolor7, XtCColor, XtRPixel, sizeof(Pixel), offset(color[7]), XtRString, "#c86400" },
247 { XtNcolor8, XtCColor, XtRPixel, sizeof(Pixel), offset(color[8]), XtRString, "#a3a3a3" },
248 { XtNcolor9, XtCColor, XtRPixel, sizeof(Pixel), offset(color[9]), XtRString, "#ebebeb" },
249 { XtNcolor10, XtCColor, XtRPixel, sizeof(Pixel), offset(color[10]), XtRString, "#a500ff" },
250 { XtNcolor11, XtCColor, XtRPixel, sizeof(Pixel), offset(color[11]), XtRString, "#fffd00" },
251 { XtNcolor12, XtCColor, XtRPixel, sizeof(Pixel), offset(color[12]), XtRString, "#ff00bc" },
252 { XtNcolor13, XtCColor, XtRPixel, sizeof(Pixel), offset(color[13]), XtRString, "#00ff00" },
253 { XtNcolor14, XtCColor, XtRPixel, sizeof(Pixel), offset(color[14]), XtRString, "#00c8ff" },
254 { XtNcolor15, XtCColor, XtRPixel, sizeof(Pixel), offset(color[15]), XtRString, "#ffcc80" },
256 { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer), offset(redraw_callbacks), XtRCallback, (XtPointer)nullptr } };
260 /* Forward declarations for Widget functions */
261 static void Initialize(AngbandWidget request, AngbandWidget new);
262 static void Redisplay(AngbandWidget w, XEvent *event, Region region);
263 static Boolean SetValues(AngbandWidget current, AngbandWidget request, AngbandWidget new, ArgList args, Cardinal *num_args);
264 static void Destroy(AngbandWidget widget);
266 /* Forward declaration for internal functions */
267 static void calculateSizeHints(AngbandWidget new);
268 static XFontStruct *getFont(AngbandWidget widget, String font, Boolean fallback);
270 /* Class record constanst */
271 AngbandClassRec angbandClassRec = { {
272 /* Core class fields initialization */
273 #define superclass (&simpleClassRec)
274 /* superclass */ (WidgetClass)superclass,
275 /* class_name */ "Angband",
276 /* widget_size */ sizeof(AngbandRec),
277 /* class_initialize */ nullptr,
278 /* class_part_initialize*/ nullptr,
279 /* class_inited */ false,
280 /* initialize */ (XtInitProc)Initialize,
281 /* initialize_hook */ nullptr,
282 /* realize */ XtInheritRealize,
283 /* actions */ nullptr,
285 /* resources */ resources,
286 /* num_resources */ XtNumber(resources),
287 /* xrm_class */ nullptrQUARK,
288 /* compress_motion */ true,
289 /* compress_exposure */ XtExposeCompressMultiple,
290 /* compress_enterleave */ true,
291 /* visible_interest */ false,
292 /* destroy */ (XtWidgetProc)Destroy,
293 /* resize */ nullptr,
294 /* expose */ (XtExposeProc)Redisplay,
295 /* set_values */ (XtSetValuesFunc)SetValues,
296 /* set_values_hook */ nullptr,
297 /* set_values_almost */ XtInheritSetValuesAlmost,
298 /* get_values_hook */ nullptr,
299 /* accept_focus */ nullptr,
300 /* version */ XtVersion,
301 /* callback_private */ nullptr,
302 /* tm_table */ nullptr,
303 /* query_geometry */ nullptr,
304 /* display_accelerator */ XtInheritDisplayAccelerator,
305 /* extension */ nullptr },
306 /* Simple class fields initialization */
307 { /* change_sensitive */ XtInheritChangeSensitive },
308 /* Angband class fields initialization */
309 { /* nothing */ 0 } };
311 /* Class record pointer */
312 WidgetClass angbandWidgetClass = (WidgetClass)&angbandClassRec;
317 static void AngbandOutputText(AngbandWidget widget, int x, int y, String txt, int len, int color)
319 /* Do nothing if the string is null */
323 /* Check the lenght, and fix it if it's below zero */
327 /* Figure out where to place the text */
328 y = y * widget->angband.fontheight + widget->angband.fontascent + widget->angband.internal_border;
329 x = x * widget->angband.fontwidth + widget->angband.internal_border;
331 /* Place the string */
332 XDrawImageString(XtDisplay(widget), XtWindow(widget), widget->angband.gc[color], x, y, txt, len);
335 static void AngbandClearArea(AngbandWidget widget, int x, int y, int w, int h, int color)
337 /* Figure out which area to clear */
338 y = y * widget->angband.fontheight + widget->angband.internal_border;
339 x = x * widget->angband.fontwidth + widget->angband.internal_border;
342 XFillRectangle(XtDisplay(widget), XtWindow(widget), widget->angband.gc[color], x, y, widget->angband.fontwidth * w, widget->angband.fontheight * h);
350 * Procedure Initialize() is called during the widget creation
351 * process. Initialize() load fonts and calculates window geometry.
352 * The request parameter is filled in by parents to this widget. The
353 * new parameter is the request parameter plus data filled in by this
354 * widget. All changes should be done to the new parameter.
356 static void Initialize(AngbandWidget request, AngbandWidget new)
359 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
360 TopLevelShellWidget parent = (TopLevelShellWidget)XtParent((Widget) new);
363 /* Fix the background color */
364 new->core.background_pixel = new->angband.color[0];
366 /* Get some information about the font */
367 new->angband.fnt = getFont(new, new->angband.font, TRUE);
368 new->angband.fontheight = new->angband.fnt->ascent + new->angband.fnt->descent;
369 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
370 new->angband.fontascent = new->angband.fnt->ascent;
372 /* Create and initialize the graphics contexts */ /* GXset? */
373 gcv.font = new->angband.fnt->fid;
374 gcv.graphics_exposures = FALSE;
375 gcv.background = new->angband.color[0];
376 for (n = 0; n < NUM_COLORS; n++) {
377 if (depth == 1 && n >= 1)
378 gcv.foreground = new->angband.color[1];
380 gcv.foreground = new->angband.color[n];
381 new->angband.gc[n] = XtGetGC((Widget) new, GCFont | GCForeground | GCBackground | GCGraphicsExposures, &gcv);
384 /* Create a special GC for highlighting */
385 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget) new)) ^ WhitePixelOfScreen(XtScreen((Widget) new));
386 gcv.function = GXxor;
387 new->angband.gc[NUM_COLORS] = XtGetGC((Widget) new, GCFunction | GCGraphicsExposures | GCForeground, &gcv);
389 /* Calculate window geometry */
390 new->core.height = new->angband.start_rows *new->angband.fontheight + 2 * new->angband.internal_border;
391 new->core.width = new->angband.start_columns *new->angband.fontwidth + 2 * new->angband.internal_border;
393 /* We need to be able to resize the Widget if the user want's to
394 change font on the fly! */
395 parent->shell.allow_shell_resize = TRUE;
397 /* Calculates all the size hints */
398 calculateSizeHints(new);
402 * Procedure Destroy() is called during the destruction of the widget.
403 * Destroy() releases and frees GCs, frees the pixmaps and frees the
406 static void Destroy(AngbandWidget widget)
411 for (n = 0; n < NUM_COLORS + 1; n++)
412 XtReleaseGC((Widget)widget, widget->angband.gc[n]);
415 XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
419 * Procedure Redisplay() is called as the result of an Expose event.
420 * Use the redraw callback to do a full redraw
422 static void Redisplay(AngbandWidget widget, XEvent *event, Region region)
424 if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
425 XtCallCallbacks((Widget)widget, XtNredrawCallback, nullptr);
429 * Font, colors and internal_border can be changed on the fly.
430 * The entire widget is redrawn if any of those parameters change (all
431 * can potentially have effects that spans the whole widget).
433 static Boolean SetValues(AngbandWidget current, AngbandWidget request, AngbandWidget new, ArgList args, Cardinal *num_args)
435 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
436 Boolean font_changed = FALSE;
437 Boolean border_changed = FALSE;
438 Boolean color_changed = FALSE;
444 if (current->angband.font != new->angband.font) {
445 /* Check if the font exists */
446 new->angband.fnt = getFont(new, new->angband.font, FALSE);
448 /* The font didn't exist */
449 if (new->angband.fnt == nullptr) {
450 new->angband.fnt = current->angband.fnt;
451 new->angband.font = current->angband.font;
452 XtWarning("Couldn't find the request font!");
455 /* Free the old font */
456 XFreeFont(XtDisplay((Widget) new), current->angband.fnt);
457 /* Update font information */
458 new->angband.fontheight = new->angband.fnt->ascent + new->angband.fnt->descent;
459 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
460 new->angband.fontascent = new->angband.fnt->ascent;
464 /* Check all colors, if one or more has changed the redo all GC's */
465 for (n = 0; n < NUM_COLORS; n++)
466 if (current->angband.color[n] != new->angband.color[n])
467 color_changed = TRUE;
469 /* Change all GC's if color or font has changed */
470 if (color_changed || font_changed) {
471 gcv.font = new->angband.fnt->fid;
472 gcv.graphics_exposures = FALSE;
473 gcv.background = new->angband.color[0];
476 for (n = 0; n < NUM_COLORS; n++) {
477 if (depth == 1 && n >= 1)
478 gcv.foreground = new->angband.color[1];
480 gcv.foreground = new->angband.color[n];
481 /* Release the old GC */
482 XtReleaseGC((Widget)current, current->angband.gc[n]);
484 new->angband.gc[n] = XtGetGC((Widget) new, GCFont | GCForeground | GCBackground | GCGraphicsExposures, &gcv);
487 /* Replace the old XOR/highlighting GC */
488 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget) new)) ^ WhitePixelOfScreen(XtScreen((Widget) new));
489 gcv.function = GXxor;
490 XtReleaseGC((Widget)current, current->angband.gc[NUM_COLORS]);
491 new->angband.gc[NUM_COLORS] = XtGetGC((Widget) new, GCFunction | GCGraphicsExposures | GCForeground, &gcv);
492 /* Fix the background color */
493 new->core.background_pixel = new->angband.color[0];
496 /* Check if internal border width has changed, used later */
497 if (current->angband.internal_border != new->angband.internal_border)
498 border_changed = TRUE;
500 /* If the font or the internal border has changed, all geometry
501 has to be recalculated */
502 if (font_changed || border_changed) {
503 /* Change window size */
504 height = (current->core.height - 2 * current->angband.internal_border) / current->angband.fontheight * new->angband.fontheight
505 + 2 * current->angband.internal_border;
506 width = (current->core.width - 2 * current->angband.internal_border) / current->angband.fontwidth * new->angband.fontwidth
507 + 2 * new->angband.internal_border;
509 /* Get the new width */
510 if (XtMakeResizeRequest((Widget) new, width, height, nullptr, nullptr) == XtGeometryNo) {
512 XtWarning("Size change denied!");
514 /* Recalculate size hints */
515 calculateSizeHints(new);
519 /* Tell it to redraw the widget if anything has changed */
520 return (font_changed || color_changed || border_changed);
524 * Calculate size hints
526 static void calculateSizeHints(AngbandWidget new)
528 TopLevelShellWidget parent = (TopLevelShellWidget)XtParent((Widget) new);
530 /* Calculate minimum size */
531 parent->wm.size_hints.min_height = new->angband.min_rows *new->angband.fontheight + 2 * new->angband.internal_border;
532 parent->wm.size_hints.min_width = new->angband.min_columns *new->angband.fontwidth + 2 * new->angband.internal_border;
533 parent->wm.size_hints.flags |= PMinSize;
535 /* Calculate maximum size */
536 parent->wm.size_hints.max_height = new->angband.max_rows *new->angband.fontheight + 2 * new->angband.internal_border;
537 parent->wm.size_hints.max_width = new->angband.max_columns *new->angband.fontwidth + 2 * new->angband.internal_border;
538 parent->wm.size_hints.flags |= PMaxSize;
540 /* Calculate increment size */
541 parent->wm.size_hints.height_inc = new->angband.fontheight;
542 parent->wm.size_hints.width_inc = new->angband.fontwidth;
543 parent->wm.size_hints.flags |= PResizeInc;
545 /* Calculate base size */
546 parent->wm.base_height = 2 * new->angband.internal_border;
547 parent->wm.base_width = 2 * new->angband.internal_border;
548 parent->wm.size_hints.flags |= PBaseSize;
554 static XFontStruct *getFont(AngbandWidget widget, String font, Boolean fallback)
556 Display *dpy = XtDisplay((Widget)widget);
558 XFontStruct *fnt = nullptr;
560 if (!(fnt = XLoadQueryFont(dpy, font)) && fallback) {
561 sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
563 if (!(fnt = XLoadQueryFont(dpy, "fixed")))
564 XtError("Can't fint the font \"fixed\"!, bailing out\n");
570 /*** The non-widget code ****/
572 #ifndef IsModifierKey
575 * Keysym macros, used on Keysyms to test for classes of symbols
576 * These were stolen from one of the X11 header files
579 #define IsKeypadKey(keysym) (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
581 #define IsCursorKey(keysym) (((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select))
583 #define IsPFKey(keysym) (((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4))
585 #define IsFunctionKey(keysym) (((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35))
587 #define IsMiscFunctionKey(keysym) (((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) < XK_KP_Space))
589 #define IsModifierKey(keysym) (((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R))
594 * Checks if the keysym is a special key or a normal key
595 * Assume that XK_MISCELLANY keysyms are special
597 #define IsSpecialKey(keysym) ((unsigned)(keysym) >= 0xFF00)
600 * Maximum number of windows XXX XXX XXX XXX
602 #define MAX_TERM_DATA 8
605 * Number of fallback resources per window
607 #define TERM_FALLBACKS 6
610 * Number of windows with special fallback resources
612 #define SPECIAL_FALLBACKS 3
615 * A structure for each "term"
620 AngbandWidget widget;
624 * An array of term_data's
626 static term_data data[MAX_TERM_DATA];
628 char *termNames[MAX_TERM_DATA] = { "angband", "mirror", "recall", "choice", "term-4", "term-5", "term-6", "term-7" };
630 Arg specialArgs[TERM_FALLBACKS][SPECIAL_FALLBACKS] = {
631 /* The main screen */
632 { { XtNstartRows, 24 }, { XtNstartColumns, 80 }, { XtNminRows, 24 }, { XtNminColumns, 80 }, { XtNmaxRows, 24 }, { XtNmaxColumns, 80 } },
634 /* The "mirror" window */
635 { { XtNstartRows, 24 }, { XtNstartColumns, 80 }, { XtNminRows, 1 }, { XtNminColumns, 1 }, { XtNmaxRows, 24 }, { XtNmaxColumns, 80 } },
637 /* The "recall" window */
638 { { XtNstartRows, 8 }, { XtNstartColumns, 80 }, { XtNminRows, 1 }, { XtNminColumns, 1 }, { XtNmaxRows, 24 }, { XtNmaxColumns, 80 } }
641 Arg defaultArgs[TERM_FALLBACKS]
642 = { { XtNstartRows, 24 }, { XtNstartColumns, 80 }, { XtNminRows, 1 }, { XtNminColumns, 1 }, { XtNmaxRows, 24 }, { XtNmaxColumns, 80 } };
645 * The application context
650 * User changable information about widgets
652 static String fallback[] = { "Angband.angband.iconName: Angband", "Angband.angband.title: Angband",
653 "Angband.mirror.iconName: Mirror", "Angband.mirror.title: Mirror", "Angband.recall.iconName: Recall",
654 "Angband.recall.title: Recall", "Angband.choice.iconName: Choice", "Angband.choice.title: Choice",
655 "Angband.term-4.iconName: Term 4", "Angband.term-4.title: Term 4", "Angband.term-5.iconName: Term 5",
656 "Angband.term-5.title: Term 5", "Angband.term-6.iconName: Term 6", "Angband.term-6.title: Term 6",
657 "Angband.term-7.iconName: Term 7", "Angband.term-7.title: Term 7", nullptr };
662 static void react_redraw(Widget widget, XtPointer client_data, XtPointer call_data)
664 term_data *old_td = (term_data *)(Term->data);
665 term_data *td = (term_data *)client_data;
667 /* Activate the proper Term */
668 Term_activate(&td->t);
670 /* Request a redraw */
673 /* Activate the old Term */
674 Term_activate(&old_td->t);
678 * Process a keypress event
680 static void react_keypress(XKeyEvent *ev)
682 int i, n, mc, ms, mo, mx;
689 /* Check for "normal" keypresses */
690 n = XLookupString(ev, buf, 125, &ks, nullptr);
695 /* Extract four "modifier flags" */
696 mc = (ev->state & ControlMask) ? TRUE : FALSE;
697 ms = (ev->state & ShiftMask) ? TRUE : FALSE;
698 mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
699 mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
701 /* Hack -- Ignore "modifier keys" */
702 if (IsModifierKey(ks))
705 /* Normal keys with no modifiers */
706 if (n && !mo && !mx && !IsSpecialKey(ks)) {
707 /* Enqueue the normal key(s) */
708 for (i = 0; buf[i]; i++)
709 Term_keypress(buf[i]);
715 /* Handle a few standard keys */
718 Term_keypress(ESCAPE);
731 Term_keypress('\010');
735 /* Hack -- Use the KeySym */
737 sprintf(msg, "%c%s%s%s%s_%lX%c", 31, mc ? "N" : "", ms ? "S" : "", mo ? "O" : "", mx ? "M" : "", (unsigned long)(ks), 13);
740 /* Hack -- Use the Keycode */
742 sprintf(msg, "%c%s%s%s%sK_%X%c", 31, mc ? "N" : "", ms ? "S" : "", mo ? "O" : "", mx ? "M" : "", ev->keycode, 13);
745 /* Enqueue the "fake" string */
746 for (i = 0; msg[i]; i++)
747 Term_keypress(msg[i]);
749 /* Hack -- dump an "extra" string */
751 /* Start the "extra" string */
754 /* Enqueue the "real" string */
755 for (i = 0; buf[i]; i++)
756 Term_keypress(buf[i]);
758 /* End the "extra" string */
763 static void handle_event(Widget widget, XtPointer client_data, XEvent *event, Boolean *continue_to_dispatch)
765 term_data *old_td = (term_data *)(Term->data);
766 term_data *td = (term_data *)client_data;
768 /* Continue to process the event by default */
769 *continue_to_dispatch = TRUE;
771 /* Activate the Term */
772 Term_activate(&td->t);
774 switch (event->type) {
776 react_keypress(&(event->xkey));
777 *continue_to_dispatch = FALSE; /* We took care of the event */
781 break; /* Huh? Shouldn't happen! */
784 /* Activate the old term */
785 Term_activate(&old_td->t);
791 * Process an event (or just check for one)
793 errr CheckEvent(bool wait)
797 /* No events ready, and told to just check */
798 if (!wait && !XtAppPending(appcon))
803 XtAppNextEvent(appcon, &event);
804 XtDispatchEvent(&event);
805 if (!XtAppPending(appcon))
813 * Handle a "special request"
815 static errr Term_xtra_xaw(int n, int v)
819 /* Handle a subset of the legal requests */
822 case TERM_XTRA_NOISE:
823 XBell(XtDisplay((Widget)data[0].widget), 100);
826 /* Flush the output */
827 case TERM_XTRA_FRESH:
828 XFlush(XtDisplay((Widget)data[0].widget));
829 /* Nonblock event-check so the flushed events can be showed */
833 /* Process random events */
834 case TERM_XTRA_BORED:
835 return (CheckEvent(0));
838 case TERM_XTRA_EVENT:
839 return (CheckEvent(v));
842 case TERM_XTRA_FLUSH:
843 while (!CheckEvent(FALSE))
848 case TERM_XTRA_DELAY:
852 /* Clear the window */
853 case TERM_XTRA_CLEAR:
854 for (i = 0; i < MAX_TERM_DATA; i++) {
855 if (Term == &data[i].t)
856 XClearWindow(XtDisplay((Widget)data[i].widget), XtWindow((Widget)data[i].widget));
866 * Erase a number of characters
868 static errr Term_wipe_xaw(int x, int y, int n)
870 term_data *td = (term_data *)(Term->data);
872 /* Erase using color 0 */
873 AngbandClearArea(td->widget, x, y, n, 1, 0);
880 * Draw the cursor (XXX by hiliting)
882 static errr Term_curs_xaw(int x, int y)
884 term_data *td = (term_data *)(Term->data);
886 /* Hilite the cursor character */
887 AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
894 * Draw a number of characters
896 static errr Term_text_xaw(int x, int y, int n, byte a, concptr s)
898 term_data *td = (term_data *)(Term->data);
901 AngbandOutputText(td->widget, x, y, (String)s, n, (a & 0x0F));
910 static void term_raise(term_data win)
912 Widget widget = (Widget)win.widget;
914 XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
918 * Initialize a term_data
920 static errr term_data_init(term_data *td, Widget topLevel, int key_buf, String name, ArgList widget_arg, Cardinal widget_arg_no)
925 /* Create the shell widget */
926 parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel, nullptr, 0);
928 /* Create the interior widget */
929 td->widget = (AngbandWidget)XtCreateManagedWidget(name, angbandWidgetClass, parent, widget_arg, widget_arg_no);
931 /* Initialize the term (full size) */
932 term_init(t, 80, 24, key_buf);
934 /* Use a "soft" cursor */
935 t->soft_cursor = TRUE;
937 /* Erase with "white space" */
938 t->attr_blank = TERM_WHITE;
942 t->xtra_hook = Term_xtra_xaw;
943 t->curs_hook = Term_curs_xaw;
944 t->wipe_hook = Term_wipe_xaw;
945 t->text_hook = Term_text_xaw;
950 /* Register the keypress event handler */
951 XtAddEventHandler((Widget)td->widget, KeyPressMask, False, (XtEventHandler)handle_event, td);
953 /* Redraw callback */
954 XtAddCallback((Widget)td->widget, XtNredrawCallback, react_redraw, td);
956 /* Realize the widget */
957 XtRealizeWidget(parent);
959 /* Make it visible */
960 XtPopup(parent, XtGrabNone);
962 /* Activate (important) */
969 * Initialization function for an X Athena Widget module to Angband
971 * Mega-Hack -- we are not given the actual "argc" and "argv" from
972 * the main program, so we fake one. Thus, we are unable to parse
973 * any "display" requests for external devices. This is okay, since
974 * we need to verify the display anyway, to work with "main.c".
983 /* One fake argument */
986 /* Save the program name */
992 /* Attempt to open the local display */
993 dpy = XOpenDisplay("");
995 /* Failure -- assume no X11 available */
999 /* Close the local display */
1003 /* Support locale processing */
1004 XtSetLanguageProc(nullptr, nullptr, nullptr);
1007 /* Initialize the toolkit */
1008 topLevel = XtAppInitialize(&appcon, "Angband", nullptr, 0, &argc, argv, fallback, nullptr, 0);
1010 /* Initialize the windows */
1011 for (i = 0; i < MAX_TERM_DATA; i++) {
1012 term_data_init(&data[i], topLevel, 1024, termNames[i], i < SPECIAL_FALLBACKS ? specialArgs[i] : defaultArgs, TERM_FALLBACKS);
1013 angband_term[i] = Term;
1016 /* Activate the "Angband" window screen */
1017 Term_activate(&data[0].t);
1019 /* Raise the "Angband" window */
1020 term_raise(data[0]);