OSDN Git Service

[fix] #41503 超能力者でゲームを開始しようとするとクラッシュ
[hengband/hengband.git] / src / main-xaw.c
1 /* File: main-xaw.c */
2
3 /* Purpose: Support for X Athena Widget based Angband */
4 /* Most code written by Torbj\vn Lindgren (tl@cd.chalmers.se) */
5
6 #ifdef USE_XAW
7
8 #include "system/angband.h"
9 #include "game-option/runtime-arguments.h"
10 #include "util/int-char-converter.h"
11
12 #ifndef __MAKEDEPEND__
13 #include <X11/Xlib.h>
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__ */
28
29
30
31 /*****************************************************
32  *
33  * Resource description
34  *
35  *****************************************************/
36
37 /* Resources:
38
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
54 x                   Position           Position        0
55 y                   Position           Position        0
56
57  */
58
59 /*
60
61 My own X Resources look like this (on a 1152x900 screen):
62
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
69
70 It's also possible to change the colors using X Resources, the
71 standard colors would look like:
72
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
89
90 And the newer colors look like:
91
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
108
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
111 wants/needs this.
112
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.
116
117 angband*color0: #ffffff
118 angband*color1: #000000
119
120  */
121
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"
147
148 /* External definitions */
149 #define COLOR_XOR 16
150 #define NUM_COLORS 16
151
152 /* C Widget type definition */
153
154 typedef struct AngbandRec *AngbandWidget;
155
156 /* C Widget class type definition */
157
158 typedef struct AngbandClassRec *AngbandWidgetClass;
159
160
161 /*
162  * New fields for the Angband widget record
163  */
164
165 typedef struct
166 {
167         /* Settable resources */
168         int               start_rows;
169         int               start_columns;
170         int               min_rows;
171         int               min_columns;
172         int               max_rows;
173         int               max_columns;
174         int               internal_border;
175         String            font;
176         Pixel             color[NUM_COLORS];
177         XtCallbackList    redraw_callbacks;
178
179         /* Private state */
180         XFontStruct       *fnt;
181         Dimension         fontheight;
182         Dimension         fontwidth;
183         Dimension         fontascent;
184         GC                gc[NUM_COLORS+1];  /* Includes a special 'xor' color */
185
186 } AngbandPart;
187
188
189 /*
190  * Full instance record declaration
191  */
192
193 typedef struct AngbandRec AngbandRec;
194
195 struct AngbandRec
196 {
197         CorePart          core;
198         SimplePart        simple;
199         AngbandPart       angband;
200 };
201
202
203 /*
204  * New fields for the Angband widget class record
205  */
206
207 typedef struct AngbandClassPart AngbandClassPart;
208
209 struct AngbandClassPart
210 {
211         int               dummy;
212 };
213
214
215 /*
216  * Full class record declaration
217  */
218
219 typedef struct AngbandClassRec AngbandClassRec;
220
221 struct AngbandClassRec
222 {
223         CoreClassPart     core_class;
224         SimpleClassPart   simple_class;
225         AngbandClassPart  angband_class;
226 };
227
228
229
230 /* Angband widget, Created by Torbj\vn Lindgren (tl@cd.chalmers.se) */
231
232 /*
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).
238  */
239
240
241 /*
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
247  * to color 3/4.
248  */
249
250 #define offset(field) XtOffsetOf(AngbandRec, angband.field)
251
252 /*
253  * Fallback resources for Angband widget
254  */
255 static XtResource resources[] =
256 {
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" },
305
306         { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
307         offset(redraw_callbacks), XtRCallback, (XtPointer)NULL }
308 };
309
310 #undef offset
311
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);
318
319 /* Forward declaration for internal functions */
320 static void calculateSizeHints(AngbandWidget new);
321 static XFontStruct *getFont(AngbandWidget widget,
322                             String font, Boolean fallback);
323
324
325 /* Class record constanst */
326 AngbandClassRec angbandClassRec =
327 {
328         {
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,
340                 /* actions              */      NULL,
341                 /* num_actions          */      0,
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,
350                 /* resize               */      NULL,
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,
359                 /* tm_table             */      NULL,
360                 /* query_geometry       */      NULL,
361                 /* display_accelerator  */      XtInheritDisplayAccelerator,
362                 /* extension            */      NULL
363         },
364         /* Simple class fields initialization */
365         {
366                 /* change_sensitive     */      XtInheritChangeSensitive
367         },
368         /* Angband class fields initialization */
369         {
370                 /* nothing              */      0
371         }
372 };
373
374 /* Class record pointer */
375 WidgetClass angbandWidgetClass = (WidgetClass) &angbandClassRec;
376
377
378 /*
379  * Public procedures
380  */
381 static void AngbandOutputText(AngbandWidget widget, int x, int y,
382                               String txt, int len, int color)
383 {
384         /* Do nothing if the string is null */
385         if (!txt || !*txt)
386                 return;
387
388         /* Check the lenght, and fix it if it's below zero */
389         if (len < 0)
390                 len = strlen(txt);
391
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;
396
397         /* Place the string */
398         XDrawImageString (XtDisplay(widget), XtWindow(widget),
399                           widget->angband.gc[color], x, y, txt, len);
400 }
401
402 static void AngbandClearArea(AngbandWidget widget,
403                              int x, int y, int w, int h, int color)
404 {
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;
408
409         /* Clear the area */
410         XFillRectangle(XtDisplay(widget), XtWindow(widget),
411                        widget->angband.gc[color],
412                        x, y, widget->angband.fontwidth*w,
413                        widget->angband.fontheight*h);
414 }
415
416 /*
417  * Private procedures
418  */
419
420 /*
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.
426  */
427 static void Initialize(AngbandWidget request, AngbandWidget new)
428 {
429         XGCValues gcv;
430         int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
431         TopLevelShellWidget parent =
432         (TopLevelShellWidget)XtParent((Widget) new);
433         int n;
434
435         /* Fix the background color */
436         new->core.background_pixel = new->angband.color[0];
437
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;
444
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++)
450         {
451                 if (depth == 1 && n >= 1)
452                         gcv.foreground = new->angband.color[1];
453                 else
454                         gcv.foreground = new->angband.color[n];
455                 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
456                                              GCBackground | GCGraphicsExposures,
457                                              &gcv);
458         }
459
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 |
466                                               GCForeground, &gcv);
467
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;
473
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;
477
478         /* Calculates all the size hints */
479         calculateSizeHints(new);
480 }
481
482 /*
483  * Procedure Destroy() is called during the destruction of the widget.
484  * Destroy() releases and frees GCs, frees the pixmaps and frees the
485  * fonts.
486  */
487 static void Destroy(AngbandWidget widget)
488 {
489         int n;
490
491         /* Free all GC's */
492         for (n = 0; n < NUM_COLORS+1; n++)
493                 XtReleaseGC((Widget)widget, widget->angband.gc[n]);
494
495         /* Free the font */
496         XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
497 }
498
499 /*
500  * Procedure Redisplay() is called as the result of an Expose event.
501  * Use the redraw callback to do a full redraw
502  */
503 static void Redisplay(AngbandWidget widget, XEvent *event, Region region)
504 {
505         if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
506                 XtCallCallbacks((Widget)widget, XtNredrawCallback, NULL);
507 }
508
509 /*
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).
513  */
514 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
515                          AngbandWidget new, ArgList args,
516                          Cardinal *num_args)
517 {
518         int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
519         Boolean font_changed = FALSE;
520         Boolean border_changed = FALSE;
521         Boolean color_changed = FALSE;
522         XGCValues gcv;
523         int height, width;
524         int n;
525
526         /* Changed font? */
527         if (current->angband.font != new->angband.font)
528         {
529                 /* Check if the font exists */
530                 new->angband.fnt = getFont(new, new->angband.font, FALSE);
531
532                 /* The font didn't exist */
533                 if (new->angband.fnt == NULL)
534                 {
535                         new->angband.fnt = current->angband.fnt;
536                         new->angband.font = current->angband.font;
537                         XtWarning("Couldn't find the request font!");
538                 }
539                 else
540                 {
541                         font_changed = TRUE;
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;
549                 }
550         }
551
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;
556
557         /* Change all GC's if color or font has changed */
558         if (color_changed || font_changed)
559         {
560                 gcv.font = new->angband.fnt->fid;
561                 gcv.graphics_exposures = FALSE;
562                 gcv.background = new->angband.color[0];
563
564                 /* Do all GC's */
565                 for (n = 0; n < NUM_COLORS; n++)
566                 {
567                         if (depth == 1 && n >= 1)
568                                 gcv.foreground = new->angband.color[1];
569                         else
570                                 gcv.foreground = new->angband.color[n];
571                         /* Release the old GC */
572                         XtReleaseGC((Widget)current, current->angband.gc[n]);
573                         /* Get the new GC */
574                         new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
575                                                      GCBackground | GCGraphicsExposures,
576                                                      &gcv);
577                 }
578
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 |
586                                                       GCForeground, &gcv);
587                 /* Fix the background color */
588                 new->core.background_pixel = new->angband.color[0];
589         }
590
591         /* Check if internal border width has changed, used later */
592         if (current->angband.internal_border != new->angband.internal_border)
593                 border_changed = TRUE;
594
595
596         /* If the font or the internal border has changed, all geometry
597         has to be recalculated */
598         if (font_changed || border_changed)
599         {
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;
607
608                 /* Get the new width */
609                 if (XtMakeResizeRequest((Widget)new, width, height, NULL, NULL) ==
610                     XtGeometryNo)
611                 {
612                         /* Not allowed */
613                         XtWarning("Size change denied!");
614                 }
615                 else
616                 {
617                         /* Recalculate size hints */
618                         calculateSizeHints(new);
619                 }
620         }
621
622         /* Tell it to redraw the widget if anything has changed */
623         return (font_changed || color_changed || border_changed);
624 }
625
626 /*
627  * Calculate size hints
628  */
629 static void calculateSizeHints(AngbandWidget new)
630 {
631         TopLevelShellWidget parent =
632         (TopLevelShellWidget)XtParent((Widget) new);
633
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;
642
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;
651
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;
656
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;
661 }
662
663 /*
664  * Load a font
665  */
666 static XFontStruct *getFont(AngbandWidget widget,
667                             String font, Boolean fallback)
668 {
669         Display *dpy = XtDisplay((Widget) widget);
670         char buf[256];
671         XFontStruct *fnt = NULL;
672
673         if (!(fnt = XLoadQueryFont(dpy, font)) && fallback)
674         {
675                 sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
676                 XtWarning(buf);
677                 if (!(fnt = XLoadQueryFont(dpy, "fixed")))
678                         XtError("Can't fint the font \"fixed\"!, bailing out\n");
679         }
680
681         return fnt;
682 }
683
684
685
686 /*** The non-widget code ****/
687
688 #ifndef IsModifierKey
689
690 /*
691  * Keysym macros, used on Keysyms to test for classes of symbols
692  * These were stolen from one of the X11 header files
693  */
694
695 #define IsKeypadKey(keysym) \
696   (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
697
698 #define IsCursorKey(keysym) \
699   (((unsigned)(keysym) >= XK_Home)     && ((unsigned)(keysym) <  XK_Select))
700
701 #define IsPFKey(keysym) \
702   (((unsigned)(keysym) >= XK_KP_F1)     && ((unsigned)(keysym) <= XK_KP_F4))
703
704 #define IsFunctionKey(keysym) \
705   (((unsigned)(keysym) >= XK_F1)       && ((unsigned)(keysym) <= XK_F35))
706
707 #define IsMiscFunctionKey(keysym) \
708   (((unsigned)(keysym) >= XK_Select)   && ((unsigned)(keysym) <  XK_KP_Space))
709
710 #define IsModifierKey(keysym) \
711   (((unsigned)(keysym) >= XK_Shift_L)  && ((unsigned)(keysym) <= XK_Hyper_R))
712
713 #endif
714
715
716 /*
717  * Checks if the keysym is a special key or a normal key
718  * Assume that XK_MISCELLANY keysyms are special
719  */
720 #define IsSpecialKey(keysym) \
721   ((unsigned)(keysym) >= 0xFF00)
722
723
724
725 /*
726  * Maximum number of windows XXX XXX XXX XXX
727  */
728 #define MAX_TERM_DATA 8
729
730 /*
731  * Number of fallback resources per window
732  */
733 #define TERM_FALLBACKS 6
734
735 /*
736  * Number of windows with special fallback resources
737  */
738 #define SPECIAL_FALLBACKS 3
739
740 /*
741  * Forward declare
742  */
743 typedef struct term_data term_data;
744
745 /*
746  * A structure for each "term"
747  */
748 struct term_data
749 {
750         term t;
751
752         AngbandWidget widget;
753 };
754
755 /*
756  * An array of term_data's
757  */
758 static term_data data[MAX_TERM_DATA];
759
760 char *termNames[MAX_TERM_DATA] =
761 {
762     "angband",
763     "mirror",
764     "recall",
765     "choice",
766     "term-4",
767     "term-5",
768     "term-6",
769     "term-7"
770 };
771
772 Arg specialArgs[TERM_FALLBACKS][SPECIAL_FALLBACKS] =
773 {
774     /* The main screen */
775     {
776         { XtNstartRows,    24},
777         { XtNstartColumns, 80},
778         { XtNminRows,      24},
779         { XtNminColumns,   80},
780         { XtNmaxRows,      24},
781         { XtNmaxColumns,   80}
782     },
783
784     /* The "mirror" window */
785     {
786         { XtNstartRows,    24},
787         { XtNstartColumns, 80},
788         { XtNminRows,      1},
789         { XtNminColumns,   1},
790         { XtNmaxRows,      24},
791         { XtNmaxColumns,   80}
792     },
793
794     /* The "recall" window */
795     {
796         { XtNstartRows,    8},
797         { XtNstartColumns, 80},
798         { XtNminRows,      1},
799         { XtNminColumns,   1},
800         { XtNmaxRows,      24},
801         { XtNmaxColumns,   80}
802     }
803 };
804
805 Arg defaultArgs[TERM_FALLBACKS] =
806 {
807         { XtNstartRows,    24},
808         { XtNstartColumns, 80},
809         { XtNminRows,      1},
810         { XtNminColumns,   1},
811         { XtNmaxRows,      24},
812         { XtNmaxColumns,   80}
813 };
814
815
816 /*
817  * The application context
818  */
819 XtAppContext appcon;
820
821 /*
822  * User changable information about widgets
823  */
824 static String fallback[] =
825 {
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",
842         NULL
843 };
844
845
846
847 /*
848  * Do a redraw
849  */
850 static void react_redraw(Widget widget,
851                          XtPointer client_data, XtPointer call_data)
852 {
853         term_data *old_td = (term_data*)(Term->data);
854         term_data *td = (term_data*)client_data;
855
856         /* Activate the proper Term */
857         Term_activate(&td->t);
858
859         /* Request a redraw */
860         Term_redraw();
861
862         /* Activate the old Term */
863         Term_activate(&old_td->t);
864 }
865
866 /*
867  * Process a keypress event
868  */
869 static void react_keypress(XKeyEvent *ev)
870 {
871         int i, n, mc, ms, mo, mx;
872
873         KeySym ks;
874
875         char buf[128];
876         char msg[128];
877
878
879         /* Check for "normal" keypresses */
880         n = XLookupString(ev, buf, 125, &ks, NULL);
881
882         /* Terminate */
883         buf[n] = '\0';
884
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;
890
891         /* Hack -- Ignore "modifier keys" */
892         if (IsModifierKey(ks)) return;
893
894         /* Normal keys with no modifiers */
895         if (n && !mo && !mx && !IsSpecialKey(ks))
896         {
897                 /* Enqueue the normal key(s) */
898                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
899
900                 /* All done */
901                 return;
902         }
903
904         /* Handle a few standard keys */
905         switch (ks)
906         {
907                 case XK_Escape:
908                 Term_keypress(ESCAPE); return;
909
910                 case XK_Return:
911                 Term_keypress('\r'); return;
912
913                 case XK_Tab:
914                 Term_keypress('\t'); return;
915
916                 case XK_Delete:
917                 case XK_BackSpace:
918                 Term_keypress('\010'); return;
919         }
920
921         /* Hack -- Use the KeySym */
922         if (ks)
923         {
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);
928         }
929
930         /* Hack -- Use the Keycode */
931         else
932         {
933                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
934                         mc ? "N" : "", ms ? "S" : "",
935                         mo ? "O" : "", mx ? "M" : "",
936                         ev->keycode, 13);
937         }
938
939         /* Enqueue the "fake" string */
940         for (i = 0; msg[i]; i++)
941                 Term_keypress(msg[i]);
942
943         /* Hack -- dump an "extra" string */
944         if (n)
945         {
946                 /* Start the "extra" string */
947                 Term_keypress(28);
948
949                 /* Enqueue the "real" string */
950                 for (i = 0; buf[i]; i++)
951                         Term_keypress(buf[i]);
952
953                 /* End the "extra" string */
954                 Term_keypress(28);
955         }
956 }
957
958
959 static void handle_event (Widget widget, XtPointer client_data, XEvent *event,
960                           Boolean *continue_to_dispatch)
961 {
962         term_data *old_td = (term_data*)(Term->data);
963         term_data *td = (term_data *)client_data;
964
965         /* Continue to process the event by default */
966         *continue_to_dispatch = TRUE;
967
968         /* Activate the Term */
969         Term_activate(&td->t);
970
971         switch (event->type)
972         {
973                 case KeyPress:
974                 react_keypress(&(event->xkey));
975                 *continue_to_dispatch = FALSE; /* We took care of the event */
976                 break;
977
978                 default:
979                 break;  /* Huh? Shouldn't happen! */
980         }
981
982         /* Activate the old term */
983         Term_activate(&old_td->t);
984
985         return;
986 }
987
988
989 /*
990  * Process an event (or just check for one)
991  */
992 errr CheckEvent(bool wait)
993 {
994         XEvent event;
995
996         /* No events ready, and told to just check */
997         if (!wait && !XtAppPending(appcon)) return 1;
998
999         /* Process */
1000         while (1)
1001         {
1002                 XtAppNextEvent(appcon, &event);
1003                 XtDispatchEvent(&event);
1004                 if (!XtAppPending(appcon)) break;
1005         }
1006
1007         return (0);
1008 }
1009
1010
1011 /*
1012  * Handle a "special request"
1013  */
1014 static errr Term_xtra_xaw(int n, int v)
1015 {
1016         int i;
1017
1018         /* Handle a subset of the legal requests */
1019         switch (n)
1020         {
1021                 /* Make a noise */
1022                 case TERM_XTRA_NOISE:
1023                 XBell(XtDisplay((Widget)data[0].widget), 100);
1024                 return (0);
1025
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 */
1030                 CheckEvent(FALSE);
1031                 return (0);
1032
1033                 /* Process random events */
1034                 case TERM_XTRA_BORED:
1035                 return (CheckEvent(0));
1036
1037                 /* Process events */
1038                 case TERM_XTRA_EVENT:
1039                 return (CheckEvent(v));
1040
1041                 /* Flush events */
1042                 case TERM_XTRA_FLUSH:
1043                 while (!CheckEvent(FALSE));
1044                 return (0);
1045
1046                 /* Delay */
1047                 case TERM_XTRA_DELAY:
1048                 usleep(1000 * v);
1049                 return (0);
1050
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));
1057                 }
1058                 return (0);
1059         }
1060
1061         /* Unknown */
1062         return (1);
1063 }
1064
1065
1066
1067 /*
1068  * Erase a number of characters
1069  */
1070 static errr Term_wipe_xaw(int x, int y, int n)
1071 {
1072         term_data *td = (term_data*)(Term->data);
1073
1074         /* Erase using color 0 */
1075         AngbandClearArea(td->widget, x, y, n, 1, 0);
1076
1077         /* Success */
1078         return (0);
1079 }
1080
1081
1082
1083 /*
1084  * Draw the cursor (XXX by hiliting)
1085  */
1086 static errr Term_curs_xaw(int x, int y)
1087 {
1088         term_data *td = (term_data*)(Term->data);
1089
1090         /* Hilite the cursor character */
1091         AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
1092
1093         /* Success */
1094         return (0);
1095 }
1096
1097
1098 /*
1099  * Draw a number of characters
1100  */
1101 static errr Term_text_xaw(int x, int y, int n, byte a, concptr s)
1102 {
1103         term_data *td = (term_data*)(Term->data);
1104
1105         /* Draw the text */
1106         AngbandOutputText(td->widget, x, y, (String)s, n, (a & 0x0F));
1107
1108         /* Success */
1109         return (0);
1110 }
1111
1112
1113 /*
1114  * Raise a term
1115  */
1116 static void term_raise(term_data win)
1117 {
1118         Widget widget = (Widget)win.widget;
1119
1120         XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
1121 }
1122
1123
1124 /*
1125  * Initialize a term_data
1126  */
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)
1130 {
1131         Widget parent;
1132         term *t = &td->t;
1133
1134         /* Create the shell widget */
1135         parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel,
1136                                     NULL, 0);
1137
1138         /* Create the interior widget */
1139         td->widget = (AngbandWidget)
1140         XtCreateManagedWidget (name, angbandWidgetClass,
1141                                parent, widget_arg, widget_arg_no);
1142
1143         /* Initialize the term (full size) */
1144         term_init(t, 80, 24, key_buf);
1145
1146         /* Use a "soft" cursor */
1147         t->soft_cursor = TRUE;
1148
1149         /* Erase with "white space" */
1150         t->attr_blank = TERM_WHITE;
1151         t->char_blank = ' ';
1152
1153         /* Hooks */
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;
1158
1159         /* Save the data */
1160         t->data = td;
1161
1162         /* Register the keypress event handler */
1163         XtAddEventHandler((Widget)td->widget, KeyPressMask,
1164                           False, (XtEventHandler) handle_event, td);
1165
1166         /* Redraw callback */
1167         XtAddCallback((Widget)td->widget, XtNredrawCallback,
1168                       react_redraw, td);
1169
1170         /* Realize the widget */
1171         XtRealizeWidget(parent);
1172
1173         /* Make it visible */
1174         XtPopup(parent, XtGrabNone);
1175
1176         /* Activate (important) */
1177         Term_activate(t);
1178
1179         return 0;
1180 }
1181
1182
1183 /*
1184  * Initialization function for an X Athena Widget module to Angband
1185  *
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".
1190  */
1191 errr init_xaw(void)
1192 {
1193         int argc, i;
1194         char *argv[2];
1195         Widget topLevel;
1196         Display *dpy;
1197
1198
1199         /* One fake argument */
1200         argc = 1;
1201
1202         /* Save the program name */
1203         argv[0] = argv0;
1204
1205         /* Terminate */
1206         argv[1] = NULL;
1207
1208
1209         /* Attempt to open the local display */
1210         dpy = XOpenDisplay("");
1211
1212         /* Failure -- assume no X11 available */
1213         if (!dpy) return (-1);
1214
1215         /* Close the local display */
1216         XCloseDisplay(dpy);
1217
1218
1219 #ifdef USE_XAW_LANG
1220         /* Support locale processing */
1221         XtSetLanguageProc(NULL, NULL, NULL);
1222 #endif
1223
1224         /* Initialize the toolkit */
1225         topLevel = XtAppInitialize (&appcon, "Angband", NULL, 0, &argc, argv,
1226                                     fallback, NULL, 0);
1227
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,
1232                             TERM_FALLBACKS);
1233             angband_term[i] = Term;
1234         }
1235
1236         /* Activate the "Angband" window screen */
1237         Term_activate(&data[0].t);
1238
1239         /* Raise the "Angband" window */
1240         term_raise(data[0]);
1241
1242         /* Success */
1243         return (0);
1244 }
1245
1246 #endif
1247