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 "system/angband.h"
9 #include "game-option/runtime-arguments.h"
10 #include "util/int-char-converter.h"
12 #ifndef __MAKEDEPEND__
14 #include <X11/StringDefs.h>
15 #include <X11/Xutil.h>
16 #include <X11/Intrinsic.h>
17 #include <X11/Shell.h>
18 #include <X11/keysym.h>
19 #include <X11/keysymdef.h>
20 #include <X11/IntrinsicP.h>
21 #include <X11/CoreP.h>
22 #include <X11/ShellP.h>
23 #include <X11/StringDefs.h>
24 #include <X11/Xaw/SimpleP.h>
25 #include <X11/Xaw/Simple.h>
26 #include <X11/Xaw/XawInit.h>
27 #endif /* __MAKEDEPEND__ */
31 /*****************************************************
33 * Resource description
35 *****************************************************/
39 Name Class RepType Default Value
40 ---- ----- ------- -------------
41 background Background Pixel XtDefaultBackground
42 border BorderColor Pixel XtDefaultForeground
43 borderWidth BorderWidth Dimension 1
44 cursor Cursor Cursor None
45 cursorName Cursor String NULL
46 destroyCallback Callback Pointer NULL
47 height Height Dimension 0
48 insensitiveBorder Insensitive Pixmap Gray
49 mappedWhenManaged MappedWhenManaged Boolean True
50 pointerColor Foreground Pixel XtDefaultForeground
51 pointerColorBackground Background Pixel XtDefaultBackground
52 sensitive Sensitive Boolean True
53 width Width Dimension 0
61 My own X Resources look like this (on a 1152x900 screen):
63 angband*angband*font: 12x24
64 angband*angband*geometry: +0+-20
65 angband*recall*font: 7x13
66 angband*recall*geometry: 80x10+0+586
67 angband*choice*font: 7x13
68 angband*choice*geometry: -0-0
70 It's also possible to change the colors using X Resources, the
71 standard colors would look like:
73 angband*color0: #000000
74 angband*color1: #ffffff
75 angband*color2: #a6a6a6
76 angband*color3: #ff6302
77 angband*color4: #ca0808
78 angband*color5: #008e18
79 angband*color6: #0000e3
80 angband*color7: #814007
81 angband*color8: #6b6b6b
82 angband*color9: #d6d6d6
83 angband*color10: #5100c2
84 angband*color11: #fdf105
85 angband*color12: #ff9259
86 angband*color13: #26cf17
87 angband*color14: #02b2f2
88 angband*color15: #b28b48
90 And the newer colors look like:
92 angband*color0: #000000
93 angband*color1: #ffffff
94 angband*color2: #d7d7d7
95 angband*color3: #ff9200
96 angband*color4: #ff0000
97 angband*color5: #00cd00
98 angband*color6: #0000fe
99 angband*color7: #c86400
100 angband*color8: #a3a3a3
101 angband*color9: #ebebeb
102 angband*color10: #a500ff
103 angband*color11: #fffd00
104 angband*color12: #ff00bc
105 angband*color13: #00ff00
106 angband*color14: #00c8ff
107 angband*color15: #ffcc80
109 Some older monochrome monitors have problem with white text on black
110 background. The new code can handle the reverse situation if the user
113 The following X Resources gives black text on white background using
114 Angband/Xaw. The other colors (2-15) isn't changed, since they're not
115 used on a monochrome monitor.
117 angband*color0: #ffffff
118 angband*color1: #000000
122 /* New resource names */
123 #define XtNstartRows "startRows"
124 #define XtNstartColumns "startColumns"
125 #define XtNminRows "minRows"
126 #define XtNminColumns "minColumns"
127 #define XtNmaxRows "maxRows"
128 #define XtNmaxColumns "maxColumns"
129 #define XtNinternalBorder "internalBorder"
130 #define XtNcolor0 "color0"
131 #define XtNcolor1 "color1"
132 #define XtNcolor2 "color2"
133 #define XtNcolor3 "color3"
134 #define XtNcolor4 "color4"
135 #define XtNcolor5 "color5"
136 #define XtNcolor6 "color6"
137 #define XtNcolor7 "color7"
138 #define XtNcolor8 "color8"
139 #define XtNcolor9 "color9"
140 #define XtNcolor10 "color10"
141 #define XtNcolor11 "color11"
142 #define XtNcolor12 "color12"
143 #define XtNcolor13 "color13"
144 #define XtNcolor14 "color14"
145 #define XtNcolor15 "color15"
146 #define XtNredrawCallback "redrawCallback"
148 /* External definitions */
150 #define NUM_COLORS 16
152 /* C Widget type definition */
154 typedef struct AngbandRec *AngbandWidget;
156 /* C Widget class type definition */
158 typedef struct AngbandClassRec *AngbandWidgetClass;
162 * New fields for the Angband widget record
167 /* Settable resources */
176 Pixel color[NUM_COLORS];
177 XtCallbackList redraw_callbacks;
181 Dimension fontheight;
183 Dimension fontascent;
184 GC gc[NUM_COLORS+1]; /* Includes a special 'xor' color */
190 * Full instance record declaration
193 typedef struct AngbandRec AngbandRec;
204 * New fields for the Angband widget class record
207 typedef struct AngbandClassPart AngbandClassPart;
209 struct AngbandClassPart
216 * Full class record declaration
219 typedef struct AngbandClassRec AngbandClassRec;
221 struct AngbandClassRec
223 CoreClassPart core_class;
224 SimpleClassPart simple_class;
225 AngbandClassPart angband_class;
230 /* Angband widget, Created by Torbj
\vn Lindgren (tl@cd.chalmers.se) */
233 * Note that it isn't as self-contained as it really should be,
234 * originally everything was output to a Pixmap which was later copied
235 * to the screen when necessary. I had to abandon that idea since
236 * Pixmaps creates big performance problems for some really old X
237 * terminals (such as 3/50's running Xkernel).
242 * The default colors used is based on the ones used in main-mac.c.
243 * The main difference is that they are gamma corrected for a gamma of
244 * 1.6. MacOS do gamma correction afterwards, but X uses raw
245 * colors. The Gamma of most color screens are about 1.5 - 1.7.
246 * Color 12 was later changed a bit so that it didn't look as similar
250 #define offset(field) XtOffsetOf(AngbandRec, angband.field)
253 * Fallback resources for Angband widget
255 static XtResource resources[] =
257 { XtNstartRows, XtCValue, XtRInt, sizeof(int),
258 offset(start_rows), XtRImmediate, (XtPointer) 24 },
259 { XtNstartColumns, XtCValue, XtRInt, sizeof(int),
260 offset(start_columns), XtRImmediate, (XtPointer) 80 },
261 { XtNminRows, XtCValue, XtRInt, sizeof(int),
262 offset(min_rows), XtRImmediate, (XtPointer) 1 },
263 { XtNminColumns, XtCValue, XtRInt, sizeof(int),
264 offset(min_columns), XtRImmediate, (XtPointer) 1 },
265 { XtNmaxRows, XtCValue, XtRInt, sizeof(int),
266 offset(max_rows), XtRImmediate, (XtPointer) 24 },
267 { XtNmaxColumns, XtCValue, XtRInt, sizeof(int),
268 offset(max_columns), XtRImmediate, (XtPointer) 80 },
269 { XtNinternalBorder, XtCValue, XtRInt, sizeof(int),
270 offset(internal_border), XtRImmediate, (XtPointer) 2 },
271 { XtNfont, XtCFont, XtRString, sizeof(char *),
272 offset(font), XtRString, "9x15" },
273 { XtNcolor0, XtCColor, XtRPixel, sizeof(Pixel),
274 offset(color[0]), XtRString, "black" },
275 { XtNcolor1, XtCColor, XtRPixel, sizeof(Pixel),
276 offset(color[1]), XtRString, "white" },
277 { XtNcolor2, XtCColor, XtRPixel, sizeof(Pixel),
278 offset(color[2]), XtRString, "#d7d7d7" },
279 { XtNcolor3, XtCColor, XtRPixel, sizeof(Pixel),
280 offset(color[3]), XtRString, "#ff9200" },
281 { XtNcolor4, XtCColor, XtRPixel, sizeof(Pixel),
282 offset(color[4]), XtRString, "#ff0000" },
283 { XtNcolor5, XtCColor, XtRPixel, sizeof(Pixel),
284 offset(color[5]), XtRString, "#00cd00" },
285 { XtNcolor6, XtCColor, XtRPixel, sizeof(Pixel),
286 offset(color[6]), XtRString, "#0000fe" },
287 { XtNcolor7, XtCColor, XtRPixel, sizeof(Pixel),
288 offset(color[7]), XtRString, "#c86400" },
289 { XtNcolor8, XtCColor, XtRPixel, sizeof(Pixel),
290 offset(color[8]), XtRString, "#a3a3a3" },
291 { XtNcolor9, XtCColor, XtRPixel, sizeof(Pixel),
292 offset(color[9]), XtRString, "#ebebeb" },
293 { XtNcolor10, XtCColor, XtRPixel, sizeof(Pixel),
294 offset(color[10]), XtRString, "#a500ff" },
295 { XtNcolor11, XtCColor, XtRPixel, sizeof(Pixel),
296 offset(color[11]), XtRString, "#fffd00" },
297 { XtNcolor12, XtCColor, XtRPixel, sizeof(Pixel),
298 offset(color[12]), XtRString, "#ff00bc" },
299 { XtNcolor13, XtCColor, XtRPixel, sizeof(Pixel),
300 offset(color[13]), XtRString, "#00ff00" },
301 { XtNcolor14, XtCColor, XtRPixel, sizeof(Pixel),
302 offset(color[14]), XtRString, "#00c8ff" },
303 { XtNcolor15, XtCColor, XtRPixel, sizeof(Pixel),
304 offset(color[15]), XtRString, "#ffcc80" },
306 { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
307 offset(redraw_callbacks), XtRCallback, (XtPointer)NULL }
312 /* Forward declarations for Widget functions */
313 static void Initialize(AngbandWidget request, AngbandWidget new);
314 static void Redisplay(AngbandWidget w, XEvent *event, Region region);
315 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
316 AngbandWidget new, ArgList args, Cardinal *num_args);
317 static void Destroy(AngbandWidget widget);
319 /* Forward declaration for internal functions */
320 static void calculateSizeHints(AngbandWidget new);
321 static XFontStruct *getFont(AngbandWidget widget,
322 String font, Boolean fallback);
325 /* Class record constanst */
326 AngbandClassRec angbandClassRec =
329 /* Core class fields initialization */
330 #define superclass (&simpleClassRec)
331 /* superclass */ (WidgetClass) superclass,
332 /* class_name */ "Angband",
333 /* widget_size */ sizeof(AngbandRec),
334 /* class_initialize */ NULL,
335 /* class_part_initialize*/ NULL,
336 /* class_inited */ FALSE,
337 /* initialize */ (XtInitProc) Initialize,
338 /* initialize_hook */ NULL,
339 /* realize */ XtInheritRealize,
342 /* resources */ resources,
343 /* num_resources */ XtNumber(resources),
344 /* xrm_class */ NULLQUARK,
345 /* compress_motion */ TRUE,
346 /* compress_exposure */ XtExposeCompressMultiple,
347 /* compress_enterleave */ TRUE,
348 /* visible_interest */ FALSE,
349 /* destroy */ (XtWidgetProc) Destroy,
351 /* expose */ (XtExposeProc) Redisplay,
352 /* set_values */ (XtSetValuesFunc) SetValues,
353 /* set_values_hook */ NULL,
354 /* set_values_almost */ XtInheritSetValuesAlmost,
355 /* get_values_hook */ NULL,
356 /* accept_focus */ NULL,
357 /* version */ XtVersion,
358 /* callback_private */ NULL,
360 /* query_geometry */ NULL,
361 /* display_accelerator */ XtInheritDisplayAccelerator,
364 /* Simple class fields initialization */
366 /* change_sensitive */ XtInheritChangeSensitive
368 /* Angband class fields initialization */
374 /* Class record pointer */
375 WidgetClass angbandWidgetClass = (WidgetClass) &angbandClassRec;
381 static void AngbandOutputText(AngbandWidget widget, int x, int y,
382 String txt, int len, int color)
384 /* Do nothing if the string is null */
388 /* Check the lenght, and fix it if it's below zero */
392 /* Figure out where to place the text */
393 y = y * widget->angband.fontheight + widget->angband.fontascent +
394 widget->angband.internal_border;
395 x = x * widget->angband.fontwidth + widget->angband.internal_border;
397 /* Place the string */
398 XDrawImageString (XtDisplay(widget), XtWindow(widget),
399 widget->angband.gc[color], x, y, txt, len);
402 static void AngbandClearArea(AngbandWidget widget,
403 int x, int y, int w, int h, int color)
405 /* Figure out which area to clear */
406 y = y * widget->angband.fontheight + widget->angband.internal_border;
407 x = x * widget->angband.fontwidth + widget->angband.internal_border;
410 XFillRectangle(XtDisplay(widget), XtWindow(widget),
411 widget->angband.gc[color],
412 x, y, widget->angband.fontwidth*w,
413 widget->angband.fontheight*h);
421 * Procedure Initialize() is called during the widget creation
422 * process. Initialize() load fonts and calculates window geometry.
423 * The request parameter is filled in by parents to this widget. The
424 * new parameter is the request parameter plus data filled in by this
425 * widget. All changes should be done to the new parameter.
427 static void Initialize(AngbandWidget request, AngbandWidget new)
430 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
431 TopLevelShellWidget parent =
432 (TopLevelShellWidget)XtParent((Widget) new);
435 /* Fix the background color */
436 new->core.background_pixel = new->angband.color[0];
438 /* Get some information about the font */
439 new->angband.fnt = getFont(new, new->angband.font, TRUE);
440 new->angband.fontheight = new->angband.fnt->ascent +
441 new->angband.fnt->descent;
442 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
443 new->angband.fontascent = new->angband.fnt->ascent;
445 /* Create and initialize the graphics contexts */ /* GXset? */
446 gcv.font = new->angband.fnt->fid;
447 gcv.graphics_exposures = FALSE;
448 gcv.background = new->angband.color[0];
449 for (n = 0; n < NUM_COLORS; n++)
451 if (depth == 1 && n >= 1)
452 gcv.foreground = new->angband.color[1];
454 gcv.foreground = new->angband.color[n];
455 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
456 GCBackground | GCGraphicsExposures,
460 /* Create a special GC for highlighting */
461 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
462 WhitePixelOfScreen(XtScreen((Widget)new));
463 gcv.function = GXxor;
464 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
465 GCGraphicsExposures |
468 /* Calculate window geometry */
469 new->core.height = new->angband.start_rows * new->angband.fontheight +
470 2 * new->angband.internal_border;
471 new->core.width = new->angband.start_columns * new->angband.fontwidth +
472 2 * new->angband.internal_border;
474 /* We need to be able to resize the Widget if the user want's to
475 change font on the fly! */
476 parent->shell.allow_shell_resize = TRUE;
478 /* Calculates all the size hints */
479 calculateSizeHints(new);
483 * Procedure Destroy() is called during the destruction of the widget.
484 * Destroy() releases and frees GCs, frees the pixmaps and frees the
487 static void Destroy(AngbandWidget widget)
492 for (n = 0; n < NUM_COLORS+1; n++)
493 XtReleaseGC((Widget)widget, widget->angband.gc[n]);
496 XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
500 * Procedure Redisplay() is called as the result of an Expose event.
501 * Use the redraw callback to do a full redraw
503 static void Redisplay(AngbandWidget widget, XEvent *event, Region region)
505 if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
506 XtCallCallbacks((Widget)widget, XtNredrawCallback, NULL);
510 * Font, colors and internal_border can be changed on the fly.
511 * The entire widget is redrawn if any of those parameters change (all
512 * can potentially have effects that spans the whole widget).
514 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
515 AngbandWidget new, ArgList args,
518 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
519 Boolean font_changed = FALSE;
520 Boolean border_changed = FALSE;
521 Boolean color_changed = FALSE;
527 if (current->angband.font != new->angband.font)
529 /* Check if the font exists */
530 new->angband.fnt = getFont(new, new->angband.font, FALSE);
532 /* The font didn't exist */
533 if (new->angband.fnt == NULL)
535 new->angband.fnt = current->angband.fnt;
536 new->angband.font = current->angband.font;
537 XtWarning("Couldn't find the request font!");
542 /* Free the old font */
543 XFreeFont(XtDisplay((Widget)new), current->angband.fnt);
544 /* Update font information */
545 new->angband.fontheight = new->angband.fnt->ascent +
546 new->angband.fnt->descent;
547 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
548 new->angband.fontascent = new->angband.fnt->ascent;
552 /* Check all colors, if one or more has changed the redo all GC's */
553 for (n = 0; n < NUM_COLORS; n++)
554 if (current->angband.color[n] != new->angband.color[n])
555 color_changed = TRUE;
557 /* Change all GC's if color or font has changed */
558 if (color_changed || font_changed)
560 gcv.font = new->angband.fnt->fid;
561 gcv.graphics_exposures = FALSE;
562 gcv.background = new->angband.color[0];
565 for (n = 0; n < NUM_COLORS; n++)
567 if (depth == 1 && n >= 1)
568 gcv.foreground = new->angband.color[1];
570 gcv.foreground = new->angband.color[n];
571 /* Release the old GC */
572 XtReleaseGC((Widget)current, current->angband.gc[n]);
574 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
575 GCBackground | GCGraphicsExposures,
579 /* Replace the old XOR/highlighting GC */
580 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
581 WhitePixelOfScreen(XtScreen((Widget)new));
582 gcv.function = GXxor;
583 XtReleaseGC((Widget)current, current->angband.gc[NUM_COLORS]);
584 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
585 GCGraphicsExposures |
587 /* Fix the background color */
588 new->core.background_pixel = new->angband.color[0];
591 /* Check if internal border width has changed, used later */
592 if (current->angband.internal_border != new->angband.internal_border)
593 border_changed = TRUE;
596 /* If the font or the internal border has changed, all geometry
597 has to be recalculated */
598 if (font_changed || border_changed)
600 /* Change window size */
601 height = (current->core.height - 2 * current->angband.internal_border) /
602 current->angband.fontheight * new->angband.fontheight +
603 2 * current->angband.internal_border;
604 width = (current->core.width - 2 * current->angband.internal_border) /
605 current->angband.fontwidth * new->angband.fontwidth +
606 2 * new->angband.internal_border;
608 /* Get the new width */
609 if (XtMakeResizeRequest((Widget)new, width, height, NULL, NULL) ==
613 XtWarning("Size change denied!");
617 /* Recalculate size hints */
618 calculateSizeHints(new);
622 /* Tell it to redraw the widget if anything has changed */
623 return (font_changed || color_changed || border_changed);
627 * Calculate size hints
629 static void calculateSizeHints(AngbandWidget new)
631 TopLevelShellWidget parent =
632 (TopLevelShellWidget)XtParent((Widget) new);
634 /* Calculate minimum size */
635 parent->wm.size_hints.min_height =
636 new->angband.min_rows * new->angband.fontheight +
637 2 * new->angband.internal_border;
638 parent->wm.size_hints.min_width =
639 new->angband.min_columns * new->angband.fontwidth +
640 2 * new->angband.internal_border;
641 parent->wm.size_hints.flags |= PMinSize;
643 /* Calculate maximum size */
644 parent->wm.size_hints.max_height =
645 new->angband.max_rows * new->angband.fontheight +
646 2 * new->angband.internal_border;
647 parent->wm.size_hints.max_width =
648 new->angband.max_columns * new->angband.fontwidth +
649 2 * new->angband.internal_border;
650 parent->wm.size_hints.flags |= PMaxSize;
652 /* Calculate increment size */
653 parent->wm.size_hints.height_inc = new->angband.fontheight;
654 parent->wm.size_hints.width_inc = new->angband.fontwidth;
655 parent->wm.size_hints.flags |= PResizeInc;
657 /* Calculate base size */
658 parent->wm.base_height = 2 * new->angband.internal_border;
659 parent->wm.base_width = 2 * new->angband.internal_border;
660 parent->wm.size_hints.flags |= PBaseSize;
666 static XFontStruct *getFont(AngbandWidget widget,
667 String font, Boolean fallback)
669 Display *dpy = XtDisplay((Widget) widget);
671 XFontStruct *fnt = NULL;
673 if (!(fnt = XLoadQueryFont(dpy, font)) && fallback)
675 sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
677 if (!(fnt = XLoadQueryFont(dpy, "fixed")))
678 XtError("Can't fint the font \"fixed\"!, bailing out\n");
686 /*** The non-widget code ****/
688 #ifndef IsModifierKey
691 * Keysym macros, used on Keysyms to test for classes of symbols
692 * These were stolen from one of the X11 header files
695 #define IsKeypadKey(keysym) \
696 (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
698 #define IsCursorKey(keysym) \
699 (((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select))
701 #define IsPFKey(keysym) \
702 (((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4))
704 #define IsFunctionKey(keysym) \
705 (((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35))
707 #define IsMiscFunctionKey(keysym) \
708 (((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) < XK_KP_Space))
710 #define IsModifierKey(keysym) \
711 (((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R))
717 * Checks if the keysym is a special key or a normal key
718 * Assume that XK_MISCELLANY keysyms are special
720 #define IsSpecialKey(keysym) \
721 ((unsigned)(keysym) >= 0xFF00)
726 * Maximum number of windows XXX XXX XXX XXX
728 #define MAX_TERM_DATA 8
731 * Number of fallback resources per window
733 #define TERM_FALLBACKS 6
736 * Number of windows with special fallback resources
738 #define SPECIAL_FALLBACKS 3
743 typedef struct term_data term_data;
746 * A structure for each "term"
752 AngbandWidget widget;
756 * An array of term_data's
758 static term_data data[MAX_TERM_DATA];
760 char *termNames[MAX_TERM_DATA] =
772 Arg specialArgs[TERM_FALLBACKS][SPECIAL_FALLBACKS] =
774 /* The main screen */
777 { XtNstartColumns, 80},
779 { XtNminColumns, 80},
784 /* The "mirror" window */
787 { XtNstartColumns, 80},
794 /* The "recall" window */
797 { XtNstartColumns, 80},
805 Arg defaultArgs[TERM_FALLBACKS] =
808 { XtNstartColumns, 80},
817 * The application context
822 * User changable information about widgets
824 static String fallback[] =
826 "Angband.angband.iconName: Angband",
827 "Angband.angband.title: Angband",
828 "Angband.mirror.iconName: Mirror",
829 "Angband.mirror.title: Mirror",
830 "Angband.recall.iconName: Recall",
831 "Angband.recall.title: Recall",
832 "Angband.choice.iconName: Choice",
833 "Angband.choice.title: Choice",
834 "Angband.term-4.iconName: Term 4",
835 "Angband.term-4.title: Term 4",
836 "Angband.term-5.iconName: Term 5",
837 "Angband.term-5.title: Term 5",
838 "Angband.term-6.iconName: Term 6",
839 "Angband.term-6.title: Term 6",
840 "Angband.term-7.iconName: Term 7",
841 "Angband.term-7.title: Term 7",
850 static void react_redraw(Widget widget,
851 XtPointer client_data, XtPointer call_data)
853 term_data *old_td = (term_data*)(Term->data);
854 term_data *td = (term_data*)client_data;
856 /* Activate the proper Term */
857 Term_activate(&td->t);
859 /* Request a redraw */
862 /* Activate the old Term */
863 Term_activate(&old_td->t);
867 * Process a keypress event
869 static void react_keypress(XKeyEvent *ev)
871 int i, n, mc, ms, mo, mx;
879 /* Check for "normal" keypresses */
880 n = XLookupString(ev, buf, 125, &ks, NULL);
885 /* Extract four "modifier flags" */
886 mc = (ev->state & ControlMask) ? TRUE : FALSE;
887 ms = (ev->state & ShiftMask) ? TRUE : FALSE;
888 mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
889 mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
891 /* Hack -- Ignore "modifier keys" */
892 if (IsModifierKey(ks)) return;
894 /* Normal keys with no modifiers */
895 if (n && !mo && !mx && !IsSpecialKey(ks))
897 /* Enqueue the normal key(s) */
898 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
904 /* Handle a few standard keys */
908 Term_keypress(ESCAPE); return;
911 Term_keypress('\r'); return;
914 Term_keypress('\t'); return;
918 Term_keypress('\010'); return;
921 /* Hack -- Use the KeySym */
924 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
925 mc ? "N" : "", ms ? "S" : "",
926 mo ? "O" : "", mx ? "M" : "",
927 (unsigned long)(ks), 13);
930 /* Hack -- Use the Keycode */
933 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
934 mc ? "N" : "", ms ? "S" : "",
935 mo ? "O" : "", mx ? "M" : "",
939 /* Enqueue the "fake" string */
940 for (i = 0; msg[i]; i++)
941 Term_keypress(msg[i]);
943 /* Hack -- dump an "extra" string */
946 /* Start the "extra" string */
949 /* Enqueue the "real" string */
950 for (i = 0; buf[i]; i++)
951 Term_keypress(buf[i]);
953 /* End the "extra" string */
959 static void handle_event (Widget widget, XtPointer client_data, XEvent *event,
960 Boolean *continue_to_dispatch)
962 term_data *old_td = (term_data*)(Term->data);
963 term_data *td = (term_data *)client_data;
965 /* Continue to process the event by default */
966 *continue_to_dispatch = TRUE;
968 /* Activate the Term */
969 Term_activate(&td->t);
974 react_keypress(&(event->xkey));
975 *continue_to_dispatch = FALSE; /* We took care of the event */
979 break; /* Huh? Shouldn't happen! */
982 /* Activate the old term */
983 Term_activate(&old_td->t);
990 * Process an event (or just check for one)
992 errr CheckEvent(bool wait)
996 /* No events ready, and told to just check */
997 if (!wait && !XtAppPending(appcon)) return 1;
1002 XtAppNextEvent(appcon, &event);
1003 XtDispatchEvent(&event);
1004 if (!XtAppPending(appcon)) break;
1012 * Handle a "special request"
1014 static errr Term_xtra_xaw(int n, int v)
1018 /* Handle a subset of the legal requests */
1022 case TERM_XTRA_NOISE:
1023 XBell(XtDisplay((Widget)data[0].widget), 100);
1026 /* Flush the output */
1027 case TERM_XTRA_FRESH:
1028 XFlush(XtDisplay((Widget)data[0].widget));
1029 /* Nonblock event-check so the flushed events can be showed */
1033 /* Process random events */
1034 case TERM_XTRA_BORED:
1035 return (CheckEvent(0));
1037 /* Process events */
1038 case TERM_XTRA_EVENT:
1039 return (CheckEvent(v));
1042 case TERM_XTRA_FLUSH:
1043 while (!CheckEvent(FALSE));
1047 case TERM_XTRA_DELAY:
1051 /* Clear the window */
1052 case TERM_XTRA_CLEAR:
1053 for (i=0; i<MAX_TERM_DATA; i++) {
1054 if (Term == &data[i].t)
1055 XClearWindow(XtDisplay((Widget)data[i].widget),
1056 XtWindow((Widget)data[i].widget));
1068 * Erase a number of characters
1070 static errr Term_wipe_xaw(int x, int y, int n)
1072 term_data *td = (term_data*)(Term->data);
1074 /* Erase using color 0 */
1075 AngbandClearArea(td->widget, x, y, n, 1, 0);
1084 * Draw the cursor (XXX by hiliting)
1086 static errr Term_curs_xaw(int x, int y)
1088 term_data *td = (term_data*)(Term->data);
1090 /* Hilite the cursor character */
1091 AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
1099 * Draw a number of characters
1101 static errr Term_text_xaw(int x, int y, int n, byte a, concptr s)
1103 term_data *td = (term_data*)(Term->data);
1106 AngbandOutputText(td->widget, x, y, (String)s, n, (a & 0x0F));
1116 static void term_raise(term_data win)
1118 Widget widget = (Widget)win.widget;
1120 XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
1125 * Initialize a term_data
1127 static errr term_data_init(term_data *td, Widget topLevel,
1128 int key_buf, String name,
1129 ArgList widget_arg, Cardinal widget_arg_no)
1134 /* Create the shell widget */
1135 parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel,
1138 /* Create the interior widget */
1139 td->widget = (AngbandWidget)
1140 XtCreateManagedWidget (name, angbandWidgetClass,
1141 parent, widget_arg, widget_arg_no);
1143 /* Initialize the term (full size) */
1144 term_init(t, 80, 24, key_buf);
1146 /* Use a "soft" cursor */
1147 t->soft_cursor = TRUE;
1149 /* Erase with "white space" */
1150 t->attr_blank = TERM_WHITE;
1151 t->char_blank = ' ';
1154 t->xtra_hook = Term_xtra_xaw;
1155 t->curs_hook = Term_curs_xaw;
1156 t->wipe_hook = Term_wipe_xaw;
1157 t->text_hook = Term_text_xaw;
1162 /* Register the keypress event handler */
1163 XtAddEventHandler((Widget)td->widget, KeyPressMask,
1164 False, (XtEventHandler) handle_event, td);
1166 /* Redraw callback */
1167 XtAddCallback((Widget)td->widget, XtNredrawCallback,
1170 /* Realize the widget */
1171 XtRealizeWidget(parent);
1173 /* Make it visible */
1174 XtPopup(parent, XtGrabNone);
1176 /* Activate (important) */
1184 * Initialization function for an X Athena Widget module to Angband
1186 * Mega-Hack -- we are not given the actual "argc" and "argv" from
1187 * the main program, so we fake one. Thus, we are unable to parse
1188 * any "display" requests for external devices. This is okay, since
1189 * we need to verify the display anyway, to work with "main.c".
1199 /* One fake argument */
1202 /* Save the program name */
1209 /* Attempt to open the local display */
1210 dpy = XOpenDisplay("");
1212 /* Failure -- assume no X11 available */
1213 if (!dpy) return (-1);
1215 /* Close the local display */
1220 /* Support locale processing */
1221 XtSetLanguageProc(NULL, NULL, NULL);
1224 /* Initialize the toolkit */
1225 topLevel = XtAppInitialize (&appcon, "Angband", NULL, 0, &argc, argv,
1228 /* Initialize the windows */
1229 for (i=0; i<MAX_TERM_DATA; i++) {
1230 term_data_init (&data[i], topLevel, 1024, termNames[i],
1231 i<SPECIAL_FALLBACKS ? specialArgs[i] : defaultArgs,
1233 angband_term[i] = Term;
1236 /* Activate the "Angband" window screen */
1237 Term_activate(&data[0].t);
1239 /* Raise the "Angband" window */
1240 term_raise(data[0]);