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) */
11 #ifndef __MAKEDEPEND__
13 #include <X11/StringDefs.h>
14 #include <X11/Xutil.h>
15 #include <X11/Intrinsic.h>
16 #include <X11/Shell.h>
17 #include <X11/keysym.h>
18 #include <X11/keysymdef.h>
19 #include <X11/IntrinsicP.h>
20 #include <X11/CoreP.h>
21 #include <X11/ShellP.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xaw/SimpleP.h>
24 #include <X11/Xaw/Simple.h>
25 #include <X11/Xaw/XawInit.h>
26 #endif /* __MAKEDEPEND__ */
30 /*****************************************************
32 * Resource description
34 *****************************************************/
38 Name Class RepType Default Value
39 ---- ----- ------- -------------
40 background Background Pixel XtDefaultBackground
41 border BorderColor Pixel XtDefaultForeground
42 borderWidth BorderWidth Dimension 1
43 cursor Cursor Cursor None
44 cursorName Cursor String NULL
45 destroyCallback Callback Pointer NULL
46 height Height Dimension 0
47 insensitiveBorder Insensitive Pixmap Gray
48 mappedWhenManaged MappedWhenManaged Boolean True
49 pointerColor Foreground Pixel XtDefaultForeground
50 pointerColorBackground Background Pixel XtDefaultBackground
51 sensitive Sensitive Boolean True
52 width Width Dimension 0
60 My own X Resources look like this (on a 1152x900 screen):
62 angband*angband*font: 12x24
63 angband*angband*geometry: +0+-20
64 angband*recall*font: 7x13
65 angband*recall*geometry: 80x10+0+586
66 angband*choice*font: 7x13
67 angband*choice*geometry: -0-0
69 It's also possible to change the colors using X Resources, the
70 standard colors would look like:
72 angband*color0: #000000
73 angband*color1: #ffffff
74 angband*color2: #a6a6a6
75 angband*color3: #ff6302
76 angband*color4: #ca0808
77 angband*color5: #008e18
78 angband*color6: #0000e3
79 angband*color7: #814007
80 angband*color8: #6b6b6b
81 angband*color9: #d6d6d6
82 angband*color10: #5100c2
83 angband*color11: #fdf105
84 angband*color12: #ff9259
85 angband*color13: #26cf17
86 angband*color14: #02b2f2
87 angband*color15: #b28b48
89 And the newer colors look like:
91 angband*color0: #000000
92 angband*color1: #ffffff
93 angband*color2: #d7d7d7
94 angband*color3: #ff9200
95 angband*color4: #ff0000
96 angband*color5: #00cd00
97 angband*color6: #0000fe
98 angband*color7: #c86400
99 angband*color8: #a3a3a3
100 angband*color9: #ebebeb
101 angband*color10: #a500ff
102 angband*color11: #fffd00
103 angband*color12: #ff00bc
104 angband*color13: #00ff00
105 angband*color14: #00c8ff
106 angband*color15: #ffcc80
108 Some older monochrome monitors have problem with white text on black
109 background. The new code can handle the reverse situation if the user
112 The following X Resources gives black text on white background using
113 Angband/Xaw. The other colors (2-15) isn't changed, since they're not
114 used on a monochrome monitor.
116 angband*color0: #ffffff
117 angband*color1: #000000
121 /* New resource names */
122 #define XtNstartRows "startRows"
123 #define XtNstartColumns "startColumns"
124 #define XtNminRows "minRows"
125 #define XtNminColumns "minColumns"
126 #define XtNmaxRows "maxRows"
127 #define XtNmaxColumns "maxColumns"
128 #define XtNinternalBorder "internalBorder"
129 #define XtNcolor0 "color0"
130 #define XtNcolor1 "color1"
131 #define XtNcolor2 "color2"
132 #define XtNcolor3 "color3"
133 #define XtNcolor4 "color4"
134 #define XtNcolor5 "color5"
135 #define XtNcolor6 "color6"
136 #define XtNcolor7 "color7"
137 #define XtNcolor8 "color8"
138 #define XtNcolor9 "color9"
139 #define XtNcolor10 "color10"
140 #define XtNcolor11 "color11"
141 #define XtNcolor12 "color12"
142 #define XtNcolor13 "color13"
143 #define XtNcolor14 "color14"
144 #define XtNcolor15 "color15"
145 #define XtNredrawCallback "redrawCallback"
147 /* External definitions */
149 #define NUM_COLORS 16
151 /* C Widget type definition */
153 typedef struct AngbandRec *AngbandWidget;
155 /* C Widget class type definition */
157 typedef struct AngbandClassRec *AngbandWidgetClass;
161 * New fields for the Angband widget record
166 /* Settable resources */
175 Pixel color[NUM_COLORS];
176 XtCallbackList redraw_callbacks;
180 Dimension fontheight;
182 Dimension fontascent;
183 GC gc[NUM_COLORS+1]; /* Includes a special 'xor' color */
189 * Full instance record declaration
192 typedef struct AngbandRec AngbandRec;
203 * New fields for the Angband widget class record
206 typedef struct AngbandClassPart AngbandClassPart;
208 struct AngbandClassPart
215 * Full class record declaration
218 typedef struct AngbandClassRec AngbandClassRec;
220 struct AngbandClassRec
222 CoreClassPart core_class;
223 SimpleClassPart simple_class;
224 AngbandClassPart angband_class;
229 /* Angband widget, Created by Torbj
\vn Lindgren (tl@cd.chalmers.se) */
232 * Note that it isn't as self-contained as it really should be,
233 * originally everything was output to a Pixmap which was later copied
234 * to the screen when necessary. I had to abandon that idea since
235 * Pixmaps creates big performance problems for some really old X
236 * terminals (such as 3/50's running Xkernel).
241 * The default colors used is based on the ones used in main-mac.c.
242 * The main difference is that they are gamma corrected for a gamma of
243 * 1.6. MacOS do gamma correction afterwards, but X uses raw
244 * colors. The Gamma of most color screens are about 1.5 - 1.7.
245 * Color 12 was later changed a bit so that it didn't look as similar
249 #define offset(field) XtOffsetOf(AngbandRec, angband.field)
252 * Fallback resources for Angband widget
254 static XtResource resources[] =
256 { XtNstartRows, XtCValue, XtRInt, sizeof(int),
257 offset(start_rows), XtRImmediate, (XtPointer) 24 },
258 { XtNstartColumns, XtCValue, XtRInt, sizeof(int),
259 offset(start_columns), XtRImmediate, (XtPointer) 80 },
260 { XtNminRows, XtCValue, XtRInt, sizeof(int),
261 offset(min_rows), XtRImmediate, (XtPointer) 1 },
262 { XtNminColumns, XtCValue, XtRInt, sizeof(int),
263 offset(min_columns), XtRImmediate, (XtPointer) 1 },
264 { XtNmaxRows, XtCValue, XtRInt, sizeof(int),
265 offset(max_rows), XtRImmediate, (XtPointer) 24 },
266 { XtNmaxColumns, XtCValue, XtRInt, sizeof(int),
267 offset(max_columns), XtRImmediate, (XtPointer) 80 },
268 { XtNinternalBorder, XtCValue, XtRInt, sizeof(int),
269 offset(internal_border), XtRImmediate, (XtPointer) 2 },
270 { XtNfont, XtCFont, XtRString, sizeof(char *),
271 offset(font), XtRString, "9x15" },
272 { XtNcolor0, XtCColor, XtRPixel, sizeof(Pixel),
273 offset(color[0]), XtRString, "black" },
274 { XtNcolor1, XtCColor, XtRPixel, sizeof(Pixel),
275 offset(color[1]), XtRString, "white" },
276 { XtNcolor2, XtCColor, XtRPixel, sizeof(Pixel),
277 offset(color[2]), XtRString, "#d7d7d7" },
278 { XtNcolor3, XtCColor, XtRPixel, sizeof(Pixel),
279 offset(color[3]), XtRString, "#ff9200" },
280 { XtNcolor4, XtCColor, XtRPixel, sizeof(Pixel),
281 offset(color[4]), XtRString, "#ff0000" },
282 { XtNcolor5, XtCColor, XtRPixel, sizeof(Pixel),
283 offset(color[5]), XtRString, "#00cd00" },
284 { XtNcolor6, XtCColor, XtRPixel, sizeof(Pixel),
285 offset(color[6]), XtRString, "#0000fe" },
286 { XtNcolor7, XtCColor, XtRPixel, sizeof(Pixel),
287 offset(color[7]), XtRString, "#c86400" },
288 { XtNcolor8, XtCColor, XtRPixel, sizeof(Pixel),
289 offset(color[8]), XtRString, "#a3a3a3" },
290 { XtNcolor9, XtCColor, XtRPixel, sizeof(Pixel),
291 offset(color[9]), XtRString, "#ebebeb" },
292 { XtNcolor10, XtCColor, XtRPixel, sizeof(Pixel),
293 offset(color[10]), XtRString, "#a500ff" },
294 { XtNcolor11, XtCColor, XtRPixel, sizeof(Pixel),
295 offset(color[11]), XtRString, "#fffd00" },
296 { XtNcolor12, XtCColor, XtRPixel, sizeof(Pixel),
297 offset(color[12]), XtRString, "#ff00bc" },
298 { XtNcolor13, XtCColor, XtRPixel, sizeof(Pixel),
299 offset(color[13]), XtRString, "#00ff00" },
300 { XtNcolor14, XtCColor, XtRPixel, sizeof(Pixel),
301 offset(color[14]), XtRString, "#00c8ff" },
302 { XtNcolor15, XtCColor, XtRPixel, sizeof(Pixel),
303 offset(color[15]), XtRString, "#ffcc80" },
307 { XtNcolor2, XtCColor, XtRPixel, sizeof(Pixel),
308 offset(color[2]), XtRString, "#a6a6a6" },
309 { XtNcolor3, XtCColor, XtRPixel, sizeof(Pixel),
310 offset(color[3]), XtRString, "#ff6302" },
311 { XtNcolor4, XtCColor, XtRPixel, sizeof(Pixel),
312 offset(color[4]), XtRString, "#ca0808" },
313 { XtNcolor5, XtCColor, XtRPixel, sizeof(Pixel),
314 offset(color[5]), XtRString, "#008e18" },
315 { XtNcolor6, XtCColor, XtRPixel, sizeof(Pixel),
316 offset(color[6]), XtRString, "#0000e3" },
317 { XtNcolor7, XtCColor, XtRPixel, sizeof(Pixel),
318 offset(color[7]), XtRString, "#814007" },
319 { XtNcolor8, XtCColor, XtRPixel, sizeof(Pixel),
320 offset(color[8]), XtRString, "#6b6b6b" },
321 { XtNcolor9, XtCColor, XtRPixel, sizeof(Pixel),
322 offset(color[9]), XtRString, "#d6d6d6" },
323 { XtNcolor10, XtCColor, XtRPixel, sizeof(Pixel),
324 offset(color[10]), XtRString, "#5100c2" },
325 { XtNcolor11, XtCColor, XtRPixel, sizeof(Pixel),
326 offset(color[11]), XtRString, "#fdf105" },
327 { XtNcolor12, XtCColor, XtRPixel, sizeof(Pixel),
328 offset(color[12]), XtRString, "#ff9259" },
329 { XtNcolor13, XtCColor, XtRPixel, sizeof(Pixel),
330 offset(color[13]), XtRString, "#26cf17" },
331 { XtNcolor14, XtCColor, XtRPixel, sizeof(Pixel),
332 offset(color[14]), XtRString, "#02b2f2" },
333 { XtNcolor15, XtCColor, XtRPixel, sizeof(Pixel),
334 offset(color[15]), XtRString, "#b28b48" },
338 { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
339 offset(redraw_callbacks), XtRCallback, (XtPointer)NULL }
344 /* Forward declarations for Widget functions */
345 static void Initialize(AngbandWidget request, AngbandWidget new);
346 static void Redisplay(AngbandWidget w, XEvent *event, Region region);
347 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
348 AngbandWidget new, ArgList args, Cardinal *num_args);
349 static void Destroy(AngbandWidget widget);
351 /* Forward declaration for internal functions */
352 static void calculateSizeHints(AngbandWidget new);
353 static XFontStruct *getFont(AngbandWidget widget,
354 String font, Boolean fallback);
357 /* Class record constanst */
358 AngbandClassRec angbandClassRec =
361 /* Core class fields initialization */
362 #define superclass (&simpleClassRec)
363 /* superclass */ (WidgetClass) superclass,
364 /* class_name */ "Angband",
365 /* widget_size */ sizeof(AngbandRec),
366 /* class_initialize */ NULL,
367 /* class_part_initialize*/ NULL,
368 /* class_inited */ FALSE,
369 /* initialize */ (XtInitProc) Initialize,
370 /* initialize_hook */ NULL,
371 /* realize */ XtInheritRealize,
374 /* resources */ resources,
375 /* num_resources */ XtNumber(resources),
376 /* xrm_class */ NULLQUARK,
377 /* compress_motion */ TRUE,
378 /* compress_exposure */ XtExposeCompressMultiple,
379 /* compress_enterleave */ TRUE,
380 /* visible_interest */ FALSE,
381 /* destroy */ (XtWidgetProc) Destroy,
383 /* expose */ (XtExposeProc) Redisplay,
384 /* set_values */ (XtSetValuesFunc) SetValues,
385 /* set_values_hook */ NULL,
386 /* set_values_almost */ XtInheritSetValuesAlmost,
387 /* get_values_hook */ NULL,
388 /* accept_focus */ NULL,
389 /* version */ XtVersion,
390 /* callback_private */ NULL,
392 /* query_geometry */ NULL,
393 /* display_accelerator */ XtInheritDisplayAccelerator,
396 /* Simple class fields initialization */
398 /* change_sensitive */ XtInheritChangeSensitive
400 /* Angband class fields initialization */
406 /* Class record pointer */
407 WidgetClass angbandWidgetClass = (WidgetClass) &angbandClassRec;
413 static void AngbandOutputText(AngbandWidget widget, int x, int y,
414 String txt, int len, int color)
416 /* Do nothing if the string is null */
420 /* Check the lenght, and fix it if it's below zero */
424 /* Figure out where to place the text */
425 y = y * widget->angband.fontheight + widget->angband.fontascent +
426 widget->angband.internal_border;
427 x = x * widget->angband.fontwidth + widget->angband.internal_border;
429 /* Place the string */
430 XDrawImageString (XtDisplay(widget), XtWindow(widget),
431 widget->angband.gc[color], x, y, txt, len);
434 static void AngbandClearArea(AngbandWidget widget,
435 int x, int y, int w, int h, int color)
437 /* Figure out which area to clear */
438 y = y * widget->angband.fontheight + widget->angband.internal_border;
439 x = x * widget->angband.fontwidth + widget->angband.internal_border;
442 XFillRectangle(XtDisplay(widget), XtWindow(widget),
443 widget->angband.gc[color],
444 x, y, widget->angband.fontwidth*w,
445 widget->angband.fontheight*h);
453 * Procedure Initialize() is called during the widget creation
454 * process. Initialize() load fonts and calculates window geometry.
455 * The request parameter is filled in by parents to this widget. The
456 * new parameter is the request parameter plus data filled in by this
457 * widget. All changes should be done to the new parameter.
459 static void Initialize(AngbandWidget request, AngbandWidget new)
462 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
463 TopLevelShellWidget parent =
464 (TopLevelShellWidget)XtParent((Widget) new);
467 /* Fix the background color */
468 new->core.background_pixel = new->angband.color[0];
470 /* Get some information about the font */
471 new->angband.fnt = getFont(new, new->angband.font, TRUE);
472 new->angband.fontheight = new->angband.fnt->ascent +
473 new->angband.fnt->descent;
474 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
475 new->angband.fontascent = new->angband.fnt->ascent;
477 /* Create and initialize the graphics contexts */ /* GXset? */
478 gcv.font = new->angband.fnt->fid;
479 gcv.graphics_exposures = FALSE;
480 gcv.background = new->angband.color[0];
481 for (n = 0; n < NUM_COLORS; n++)
483 if (depth == 1 && n >= 1)
484 gcv.foreground = new->angband.color[1];
486 gcv.foreground = new->angband.color[n];
487 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
488 GCBackground | GCGraphicsExposures,
492 /* Create a special GC for highlighting */
493 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
494 WhitePixelOfScreen(XtScreen((Widget)new));
495 gcv.function = GXxor;
496 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
497 GCGraphicsExposures |
500 /* Calculate window geometry */
501 new->core.height = new->angband.start_rows * new->angband.fontheight +
502 2 * new->angband.internal_border;
503 new->core.width = new->angband.start_columns * new->angband.fontwidth +
504 2 * new->angband.internal_border;
506 /* We need to be able to resize the Widget if the user want's to
507 change font on the fly! */
508 parent->shell.allow_shell_resize = TRUE;
510 /* Calculates all the size hints */
511 calculateSizeHints(new);
515 * Procedure Destroy() is called during the destruction of the widget.
516 * Destroy() releases and frees GCs, frees the pixmaps and frees the
519 static void Destroy(AngbandWidget widget)
524 for (n = 0; n < NUM_COLORS+1; n++)
525 XtReleaseGC((Widget)widget, widget->angband.gc[n]);
528 XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
532 * Procedure Redisplay() is called as the result of an Expose event.
533 * Use the redraw callback to do a full redraw
535 static void Redisplay(AngbandWidget widget, XEvent *event, Region region)
537 if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
538 XtCallCallbacks((Widget)widget, XtNredrawCallback, NULL);
542 * Font, colors and internal_border can be changed on the fly.
543 * The entire widget is redrawn if any of those parameters change (all
544 * can potentially have effects that spans the whole widget).
546 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
547 AngbandWidget new, ArgList args,
550 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
551 Boolean font_changed = FALSE;
552 Boolean border_changed = FALSE;
553 Boolean color_changed = FALSE;
559 if (current->angband.font != new->angband.font)
561 /* Check if the font exists */
562 new->angband.fnt = getFont(new, new->angband.font, FALSE);
564 /* The font didn't exist */
565 if (new->angband.fnt == NULL)
567 new->angband.fnt = current->angband.fnt;
568 new->angband.font = current->angband.font;
569 XtWarning("Couldn't find the request font!");
574 /* Free the old font */
575 XFreeFont(XtDisplay((Widget)new), current->angband.fnt);
576 /* Update font information */
577 new->angband.fontheight = new->angband.fnt->ascent +
578 new->angband.fnt->descent;
579 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
580 new->angband.fontascent = new->angband.fnt->ascent;
584 /* Check all colors, if one or more has changed the redo all GC's */
585 for (n = 0; n < NUM_COLORS; n++)
586 if (current->angband.color[n] != new->angband.color[n])
587 color_changed = TRUE;
589 /* Change all GC's if color or font has changed */
590 if (color_changed || font_changed)
592 gcv.font = new->angband.fnt->fid;
593 gcv.graphics_exposures = FALSE;
594 gcv.background = new->angband.color[0];
597 for (n = 0; n < NUM_COLORS; n++)
599 if (depth == 1 && n >= 1)
600 gcv.foreground = new->angband.color[1];
602 gcv.foreground = new->angband.color[n];
603 /* Release the old GC */
604 XtReleaseGC((Widget)current, current->angband.gc[n]);
606 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
607 GCBackground | GCGraphicsExposures,
611 /* Replace the old XOR/highlighting GC */
612 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
613 WhitePixelOfScreen(XtScreen((Widget)new));
614 gcv.function = GXxor;
615 XtReleaseGC((Widget)current, current->angband.gc[NUM_COLORS]);
616 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
617 GCGraphicsExposures |
619 /* Fix the background color */
620 new->core.background_pixel = new->angband.color[0];
623 /* Check if internal border width has changed, used later */
624 if (current->angband.internal_border != new->angband.internal_border)
625 border_changed = TRUE;
628 /* If the font or the internal border has changed, all geometry
629 has to be recalculated */
630 if (font_changed || border_changed)
632 /* Change window size */
633 height = (current->core.height - 2 * current->angband.internal_border) /
634 current->angband.fontheight * new->angband.fontheight +
635 2 * current->angband.internal_border;
636 width = (current->core.width - 2 * current->angband.internal_border) /
637 current->angband.fontwidth * new->angband.fontwidth +
638 2 * new->angband.internal_border;
640 /* Get the new width */
641 if (XtMakeResizeRequest((Widget)new, width, height, NULL, NULL) ==
645 XtWarning("Size change denied!");
649 /* Recalculate size hints */
650 calculateSizeHints(new);
654 /* Tell it to redraw the widget if anything has changed */
655 return (font_changed || color_changed || border_changed);
659 * Calculate size hints
661 static void calculateSizeHints(AngbandWidget new)
663 TopLevelShellWidget parent =
664 (TopLevelShellWidget)XtParent((Widget) new);
666 /* Calculate minimum size */
667 parent->wm.size_hints.min_height =
668 new->angband.min_rows * new->angband.fontheight +
669 2 * new->angband.internal_border;
670 parent->wm.size_hints.min_width =
671 new->angband.min_columns * new->angband.fontwidth +
672 2 * new->angband.internal_border;
673 parent->wm.size_hints.flags |= PMinSize;
675 /* Calculate maximum size */
676 parent->wm.size_hints.max_height =
677 new->angband.max_rows * new->angband.fontheight +
678 2 * new->angband.internal_border;
679 parent->wm.size_hints.max_width =
680 new->angband.max_columns * new->angband.fontwidth +
681 2 * new->angband.internal_border;
682 parent->wm.size_hints.flags |= PMaxSize;
684 /* Calculate increment size */
685 parent->wm.size_hints.height_inc = new->angband.fontheight;
686 parent->wm.size_hints.width_inc = new->angband.fontwidth;
687 parent->wm.size_hints.flags |= PResizeInc;
689 /* Calculate base size */
690 parent->wm.base_height = 2 * new->angband.internal_border;
691 parent->wm.base_width = 2 * new->angband.internal_border;
692 parent->wm.size_hints.flags |= PBaseSize;
698 static XFontStruct *getFont(AngbandWidget widget,
699 String font, Boolean fallback)
701 Display *dpy = XtDisplay((Widget) widget);
703 XFontStruct *fnt = NULL;
705 if (!(fnt = XLoadQueryFont(dpy, font)) && fallback)
707 sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
709 if (!(fnt = XLoadQueryFont(dpy, "fixed")))
710 XtError("Can't fint the font \"fixed\"!, bailing out\n");
718 /*** The non-widget code ****/
720 #ifndef IsModifierKey
723 * Keysym macros, used on Keysyms to test for classes of symbols
724 * These were stolen from one of the X11 header files
727 #define IsKeypadKey(keysym) \
728 (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
730 #define IsCursorKey(keysym) \
731 (((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select))
733 #define IsPFKey(keysym) \
734 (((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4))
736 #define IsFunctionKey(keysym) \
737 (((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35))
739 #define IsMiscFunctionKey(keysym) \
740 (((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) < XK_KP_Space))
742 #define IsModifierKey(keysym) \
743 (((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R))
749 * Checks if the keysym is a special key or a normal key
750 * Assume that XK_MISCELLANY keysyms are special
752 #define IsSpecialKey(keysym) \
753 ((unsigned)(keysym) >= 0xFF00)
758 * Maximum number of windows XXX XXX XXX XXX
760 #define MAX_TERM_DATA 8
763 * Number of fallback resources per window
765 #define TERM_FALLBACKS 6
768 * Number of windows with special fallback resources
770 #define SPECIAL_FALLBACKS 3
775 typedef struct term_data term_data;
778 * A structure for each "term"
784 AngbandWidget widget;
788 * An array of term_data's
790 static term_data data[MAX_TERM_DATA];
792 char *termNames[MAX_TERM_DATA] =
804 Arg specialArgs[TERM_FALLBACKS][SPECIAL_FALLBACKS] =
806 /* The main screen */
809 { XtNstartColumns, 80},
811 { XtNminColumns, 80},
816 /* The "mirror" window */
819 { XtNstartColumns, 80},
826 /* The "recall" window */
829 { XtNstartColumns, 80},
837 Arg defaultArgs[TERM_FALLBACKS] =
840 { XtNstartColumns, 80},
849 * The application context
854 * User changable information about widgets
856 static String fallback[] =
858 "Angband.angband.iconName: Angband",
859 "Angband.angband.title: Angband",
860 "Angband.mirror.iconName: Mirror",
861 "Angband.mirror.title: Mirror",
862 "Angband.recall.iconName: Recall",
863 "Angband.recall.title: Recall",
864 "Angband.choice.iconName: Choice",
865 "Angband.choice.title: Choice",
866 "Angband.term-4.iconName: Term 4",
867 "Angband.term-4.title: Term 4",
868 "Angband.term-5.iconName: Term 5",
869 "Angband.term-5.title: Term 5",
870 "Angband.term-6.iconName: Term 6",
871 "Angband.term-6.title: Term 6",
872 "Angband.term-7.iconName: Term 7",
873 "Angband.term-7.title: Term 7",
882 static void react_redraw(Widget widget,
883 XtPointer client_data, XtPointer call_data)
885 term_data *old_td = (term_data*)(Term->data);
886 term_data *td = (term_data*)client_data;
888 /* Activate the proper Term */
889 Term_activate(&td->t);
891 /* Request a redraw */
894 /* Activate the old Term */
895 Term_activate(&old_td->t);
899 * Process a keypress event
901 static void react_keypress(XKeyEvent *ev)
903 int i, n, mc, ms, mo, mx;
911 /* Check for "normal" keypresses */
912 n = XLookupString(ev, buf, 125, &ks, NULL);
917 /* Extract four "modifier flags" */
918 mc = (ev->state & ControlMask) ? TRUE : FALSE;
919 ms = (ev->state & ShiftMask) ? TRUE : FALSE;
920 mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
921 mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
923 /* Hack -- Ignore "modifier keys" */
924 if (IsModifierKey(ks)) return;
926 /* Normal keys with no modifiers */
927 if (n && !mo && !mx && !IsSpecialKey(ks))
929 /* Enqueue the normal key(s) */
930 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
936 /* Handle a few standard keys */
940 Term_keypress(ESCAPE); return;
943 Term_keypress('\r'); return;
946 Term_keypress('\t'); return;
950 Term_keypress('\010'); return;
953 /* Hack -- Use the KeySym */
956 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
957 mc ? "N" : "", ms ? "S" : "",
958 mo ? "O" : "", mx ? "M" : "",
959 (unsigned long)(ks), 13);
962 /* Hack -- Use the Keycode */
965 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
966 mc ? "N" : "", ms ? "S" : "",
967 mo ? "O" : "", mx ? "M" : "",
971 /* Enqueue the "fake" string */
972 for (i = 0; msg[i]; i++)
973 Term_keypress(msg[i]);
975 /* Hack -- dump an "extra" string */
978 /* Start the "extra" string */
981 /* Enqueue the "real" string */
982 for (i = 0; buf[i]; i++)
983 Term_keypress(buf[i]);
985 /* End the "extra" string */
991 static void handle_event (Widget widget, XtPointer client_data, XEvent *event,
992 Boolean *continue_to_dispatch)
994 term_data *old_td = (term_data*)(Term->data);
995 term_data *td = (term_data *)client_data;
997 /* Continue to process the event by default */
998 *continue_to_dispatch = TRUE;
1000 /* Activate the Term */
1001 Term_activate(&td->t);
1003 switch (event->type)
1006 react_keypress(&(event->xkey));
1007 *continue_to_dispatch = FALSE; /* We took care of the event */
1011 break; /* Huh? Shouldn't happen! */
1014 /* Activate the old term */
1015 Term_activate(&old_td->t);
1022 * Process an event (or just check for one)
1024 errr CheckEvent(bool wait)
1028 /* No events ready, and told to just check */
1029 if (!wait && !XtAppPending(appcon)) return 1;
1034 XtAppNextEvent(appcon, &event);
1035 XtDispatchEvent(&event);
1036 if (!XtAppPending(appcon)) break;
1044 * Handle a "special request"
1046 static errr Term_xtra_xaw(int n, int v)
1050 /* Handle a subset of the legal requests */
1054 case TERM_XTRA_NOISE:
1055 XBell(XtDisplay((Widget)data[0].widget), 100);
1058 /* Flush the output */
1059 case TERM_XTRA_FRESH:
1060 XFlush(XtDisplay((Widget)data[0].widget));
1061 /* Nonblock event-check so the flushed events can be showed */
1065 /* Process random events */
1066 case TERM_XTRA_BORED:
1067 return (CheckEvent(0));
1069 /* Process events */
1070 case TERM_XTRA_EVENT:
1071 return (CheckEvent(v));
1074 case TERM_XTRA_FLUSH:
1075 while (!CheckEvent(FALSE));
1079 case TERM_XTRA_DELAY:
1083 /* Clear the window */
1084 case TERM_XTRA_CLEAR:
1085 for (i=0; i<MAX_TERM_DATA; i++) {
1086 if (Term == &data[i].t)
1087 XClearWindow(XtDisplay((Widget)data[i].widget),
1088 XtWindow((Widget)data[i].widget));
1100 * Erase a number of characters
1102 static errr Term_wipe_xaw(int x, int y, int n)
1104 term_data *td = (term_data*)(Term->data);
1106 /* Erase using color 0 */
1107 AngbandClearArea(td->widget, x, y, n, 1, 0);
1116 * Draw the cursor (XXX by hiliting)
1118 static errr Term_curs_xaw(int x, int y)
1120 term_data *td = (term_data*)(Term->data);
1122 /* Hilite the cursor character */
1123 AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
1131 * Draw a number of characters
1133 static errr Term_text_xaw(int x, int y, int n, byte a, cptr s)
1135 term_data *td = (term_data*)(Term->data);
1138 AngbandOutputText(td->widget, x, y, (String)s, n, (a & 0x0F));
1148 static void term_raise(term_data win)
1150 Widget widget = (Widget)win.widget;
1152 XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
1157 * Initialize a term_data
1159 static errr term_data_init(term_data *td, Widget topLevel,
1160 int key_buf, String name,
1161 ArgList widget_arg, Cardinal widget_arg_no)
1166 /* Create the shell widget */
1167 parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel,
1170 /* Create the interior widget */
1171 td->widget = (AngbandWidget)
1172 XtCreateManagedWidget (name, angbandWidgetClass,
1173 parent, widget_arg, widget_arg_no);
1175 /* Initialize the term (full size) */
1176 term_init(t, 80, 24, key_buf);
1178 /* Use a "soft" cursor */
1179 t->soft_cursor = TRUE;
1181 /* Erase with "white space" */
1182 t->attr_blank = TERM_WHITE;
1183 t->char_blank = ' ';
1186 t->xtra_hook = Term_xtra_xaw;
1187 t->curs_hook = Term_curs_xaw;
1188 t->wipe_hook = Term_wipe_xaw;
1189 t->text_hook = Term_text_xaw;
1194 /* Register the keypress event handler */
1195 XtAddEventHandler((Widget)td->widget, KeyPressMask,
1196 False, (XtEventHandler) handle_event, td);
1198 /* Redraw callback */
1199 XtAddCallback((Widget)td->widget, XtNredrawCallback,
1202 /* Realize the widget */
1203 XtRealizeWidget(parent);
1205 /* Make it visible */
1206 XtPopup(parent, XtGrabNone);
1208 /* Activate (important) */
1216 * Initialization function for an X Athena Widget module to Angband
1218 * Mega-Hack -- we are not given the actual "argc" and "argv" from
1219 * the main program, so we fake one. Thus, we are unable to parse
1220 * any "display" requests for external devices. This is okay, since
1221 * we need to verify the display anyway, to work with "main.c".
1231 /* One fake argument */
1234 /* Save the program name */
1241 /* Attempt to open the local display */
1242 dpy = XOpenDisplay("");
1244 /* Failure -- assume no X11 available */
1245 if (!dpy) return (-1);
1247 /* Close the local display */
1252 /* Support locale processing */
1253 XtSetLanguageProc(NULL, NULL, NULL);
1256 /* Initialize the toolkit */
1257 topLevel = XtAppInitialize (&appcon, "Angband", NULL, 0, &argc, argv,
1260 /* Initialize the windows */
1261 for (i=0; i<MAX_TERM_DATA; i++) {
1262 term_data_init (&data[i], topLevel, 1024, termNames[i],
1263 i<SPECIAL_FALLBACKS ? specialArgs[i] : defaultArgs,
1265 angband_term[i] = Term;
1268 /* Activate the "Angband" window screen */
1269 Term_activate(&data[0].t);
1271 /* Raise the "Angband" window */
1272 term_raise(data[0]);