OSDN Git Service

[Refactor] #37353 main-win.c 以外のmain*.cについて、'if 0'のプリプロを削除 / Removed preprocessor...
[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 "angband.h"
9
10
11 #ifndef __MAKEDEPEND__
12 #include <X11/Xlib.h>
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__ */
27
28
29
30 /*****************************************************
31  *
32  * Resource description
33  *
34  *****************************************************/
35
36 /* Resources:
37
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
53 x                   Position           Position        0
54 y                   Position           Position        0
55
56  */
57
58 /*
59
60 My own X Resources look like this (on a 1152x900 screen):
61
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
68
69 It's also possible to change the colors using X Resources, the
70 standard colors would look like:
71
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
88
89 And the newer colors look like:
90
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
107
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
110 wants/needs this.
111
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.
115
116 angband*color0: #ffffff
117 angband*color1: #000000
118
119  */
120
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"
146
147 /* External definitions */
148 #define COLOR_XOR 16
149 #define NUM_COLORS 16
150
151 /* C Widget type definition */
152
153 typedef struct AngbandRec *AngbandWidget;
154
155 /* C Widget class type definition */
156
157 typedef struct AngbandClassRec *AngbandWidgetClass;
158
159
160 /*
161  * New fields for the Angband widget record
162  */
163
164 typedef struct
165 {
166         /* Settable resources */
167         int               start_rows;
168         int               start_columns;
169         int               min_rows;
170         int               min_columns;
171         int               max_rows;
172         int               max_columns;
173         int               internal_border;
174         String            font;
175         Pixel             color[NUM_COLORS];
176         XtCallbackList    redraw_callbacks;
177
178         /* Private state */
179         XFontStruct       *fnt;
180         Dimension         fontheight;
181         Dimension         fontwidth;
182         Dimension         fontascent;
183         GC                gc[NUM_COLORS+1];  /* Includes a special 'xor' color */
184
185 } AngbandPart;
186
187
188 /*
189  * Full instance record declaration
190  */
191
192 typedef struct AngbandRec AngbandRec;
193
194 struct AngbandRec
195 {
196         CorePart          core;
197         SimplePart        simple;
198         AngbandPart       angband;
199 };
200
201
202 /*
203  * New fields for the Angband widget class record
204  */
205
206 typedef struct AngbandClassPart AngbandClassPart;
207
208 struct AngbandClassPart
209 {
210         int               dummy;
211 };
212
213
214 /*
215  * Full class record declaration
216  */
217
218 typedef struct AngbandClassRec AngbandClassRec;
219
220 struct AngbandClassRec
221 {
222         CoreClassPart     core_class;
223         SimpleClassPart   simple_class;
224         AngbandClassPart  angband_class;
225 };
226
227
228
229 /* Angband widget, Created by Torbj\vn Lindgren (tl@cd.chalmers.se) */
230
231 /*
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).
237  */
238
239
240 /*
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
246  * to color 3/4.
247  */
248
249 #define offset(field) XtOffsetOf(AngbandRec, angband.field)
250
251 /*
252  * Fallback resources for Angband widget
253  */
254 static XtResource resources[] =
255 {
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" },
304
305         { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
306         offset(redraw_callbacks), XtRCallback, (XtPointer)NULL }
307 };
308
309 #undef offset
310
311 /* Forward declarations for Widget functions */
312 static void Initialize(AngbandWidget request, AngbandWidget new);
313 static void Redisplay(AngbandWidget w, XEvent *event, Region region);
314 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
315                          AngbandWidget new, ArgList args, Cardinal *num_args);
316 static void Destroy(AngbandWidget widget);
317
318 /* Forward declaration for internal functions */
319 static void calculateSizeHints(AngbandWidget new);
320 static XFontStruct *getFont(AngbandWidget widget,
321                             String font, Boolean fallback);
322
323
324 /* Class record constanst */
325 AngbandClassRec angbandClassRec =
326 {
327         {
328                 /* Core class fields initialization */
329 #define superclass              (&simpleClassRec)
330                 /* superclass           */      (WidgetClass) superclass,
331                 /* class_name           */      "Angband",
332                 /* widget_size          */      sizeof(AngbandRec),
333                 /* class_initialize     */      NULL,
334                 /* class_part_initialize*/      NULL,
335                 /* class_inited         */      FALSE,
336                 /* initialize           */      (XtInitProc) Initialize,
337                 /* initialize_hook      */      NULL,
338                 /* realize              */      XtInheritRealize,
339                 /* actions              */      NULL,
340                 /* num_actions          */      0,
341                 /* resources            */      resources,
342                 /* num_resources        */      XtNumber(resources),
343                 /* xrm_class            */      NULLQUARK,
344                 /* compress_motion      */      TRUE,
345                 /* compress_exposure    */      XtExposeCompressMultiple,
346                 /* compress_enterleave  */      TRUE,
347                 /* visible_interest     */      FALSE,
348                 /* destroy              */      (XtWidgetProc) Destroy,
349                 /* resize               */      NULL,
350                 /* expose               */      (XtExposeProc) Redisplay,
351                 /* set_values           */      (XtSetValuesFunc) SetValues,
352                 /* set_values_hook      */      NULL,
353                 /* set_values_almost    */      XtInheritSetValuesAlmost,
354                 /* get_values_hook      */      NULL,
355                 /* accept_focus         */      NULL,
356                 /* version              */      XtVersion,
357                 /* callback_private     */      NULL,
358                 /* tm_table             */      NULL,
359                 /* query_geometry       */      NULL,
360                 /* display_accelerator  */      XtInheritDisplayAccelerator,
361                 /* extension            */      NULL
362         },
363         /* Simple class fields initialization */
364         {
365                 /* change_sensitive     */      XtInheritChangeSensitive
366         },
367         /* Angband class fields initialization */
368         {
369                 /* nothing              */      0
370         }
371 };
372
373 /* Class record pointer */
374 WidgetClass angbandWidgetClass = (WidgetClass) &angbandClassRec;
375
376
377 /*
378  * Public procedures
379  */
380 static void AngbandOutputText(AngbandWidget widget, int x, int y,
381                               String txt, int len, int color)
382 {
383         /* Do nothing if the string is null */
384         if (!txt || !*txt)
385                 return;
386
387         /* Check the lenght, and fix it if it's below zero */
388         if (len < 0)
389                 len = strlen(txt);
390
391         /* Figure out where to place the text */
392         y = y * widget->angband.fontheight + widget->angband.fontascent +
393         widget->angband.internal_border;
394         x = x * widget->angband.fontwidth + widget->angband.internal_border;
395
396         /* Place the string */
397         XDrawImageString (XtDisplay(widget), XtWindow(widget),
398                           widget->angband.gc[color], x, y, txt, len);
399 }
400
401 static void AngbandClearArea(AngbandWidget widget,
402                              int x, int y, int w, int h, int color)
403 {
404         /* Figure out which area to clear */
405         y = y * widget->angband.fontheight + widget->angband.internal_border;
406         x = x * widget->angband.fontwidth + widget->angband.internal_border;
407
408         /* Clear the area */
409         XFillRectangle(XtDisplay(widget), XtWindow(widget),
410                        widget->angband.gc[color],
411                        x, y, widget->angband.fontwidth*w,
412                        widget->angband.fontheight*h);
413 }
414
415 /*
416  * Private procedures
417  */
418
419 /*
420  * Procedure Initialize() is called during the widget creation
421  * process.  Initialize() load fonts and calculates window geometry.
422  * The request parameter is filled in by parents to this widget.  The
423  * new parameter is the request parameter plus data filled in by this
424  * widget. All changes should be done to the new parameter.
425  */
426 static void Initialize(AngbandWidget request, AngbandWidget new)
427 {
428         XGCValues gcv;
429         int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
430         TopLevelShellWidget parent =
431         (TopLevelShellWidget)XtParent((Widget) new);
432         int n;
433
434         /* Fix the background color */
435         new->core.background_pixel = new->angband.color[0];
436
437         /* Get some information about the font */
438         new->angband.fnt = getFont(new, new->angband.font, TRUE);
439         new->angband.fontheight = new->angband.fnt->ascent +
440         new->angband.fnt->descent;
441         new->angband.fontwidth = new->angband.fnt->max_bounds.width;
442         new->angband.fontascent = new->angband.fnt->ascent;
443
444         /* Create and initialize the graphics contexts */ /* GXset? */
445         gcv.font = new->angband.fnt->fid;
446         gcv.graphics_exposures = FALSE;
447         gcv.background = new->angband.color[0];
448         for (n = 0; n < NUM_COLORS; n++)
449         {
450                 if (depth == 1 && n >= 1)
451                         gcv.foreground = new->angband.color[1];
452                 else
453                         gcv.foreground = new->angband.color[n];
454                 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
455                                              GCBackground | GCGraphicsExposures,
456                                              &gcv);
457         }
458
459         /* Create a special GC for highlighting */
460         gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
461         WhitePixelOfScreen(XtScreen((Widget)new));
462         gcv.function = GXxor;
463         new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
464                                               GCGraphicsExposures |
465                                               GCForeground, &gcv);
466
467         /* Calculate window geometry */
468         new->core.height = new->angband.start_rows * new->angband.fontheight +
469         2 * new->angband.internal_border;
470         new->core.width = new->angband.start_columns * new->angband.fontwidth +
471         2 * new->angband.internal_border;
472
473         /* We need to be able to resize the Widget if the user want's to
474         change font on the fly! */
475         parent->shell.allow_shell_resize = TRUE;
476
477         /* Calculates all the size hints */
478         calculateSizeHints(new);
479 }
480
481 /*
482  * Procedure Destroy() is called during the destruction of the widget.
483  * Destroy() releases and frees GCs, frees the pixmaps and frees the
484  * fonts.
485  */
486 static void Destroy(AngbandWidget widget)
487 {
488         int n;
489
490         /* Free all GC's */
491         for (n = 0; n < NUM_COLORS+1; n++)
492                 XtReleaseGC((Widget)widget, widget->angband.gc[n]);
493
494         /* Free the font */
495         XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
496 }
497
498 /*
499  * Procedure Redisplay() is called as the result of an Expose event.
500  * Use the redraw callback to do a full redraw
501  */
502 static void Redisplay(AngbandWidget widget, XEvent *event, Region region)
503 {
504         if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
505                 XtCallCallbacks((Widget)widget, XtNredrawCallback, NULL);
506 }
507
508 /*
509  * Font, colors and internal_border can be changed on the fly.
510  * The entire widget is redrawn if any of those parameters change (all
511  * can potentially have effects that spans the whole widget).
512  */
513 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
514                          AngbandWidget new, ArgList args,
515                          Cardinal *num_args)
516 {
517         int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
518         Boolean font_changed = FALSE;
519         Boolean border_changed = FALSE;
520         Boolean color_changed = FALSE;
521         XGCValues gcv;
522         int height, width;
523         int n;
524
525         /* Changed font? */
526         if (current->angband.font != new->angband.font)
527         {
528                 /* Check if the font exists */
529                 new->angband.fnt = getFont(new, new->angband.font, FALSE);
530
531                 /* The font didn't exist */
532                 if (new->angband.fnt == NULL)
533                 {
534                         new->angband.fnt = current->angband.fnt;
535                         new->angband.font = current->angband.font;
536                         XtWarning("Couldn't find the request font!");
537                 }
538                 else
539                 {
540                         font_changed = TRUE;
541                         /* Free the old font */
542                         XFreeFont(XtDisplay((Widget)new), current->angband.fnt);
543                         /* Update font information */
544                         new->angband.fontheight = new->angband.fnt->ascent +
545                         new->angband.fnt->descent;
546                         new->angband.fontwidth = new->angband.fnt->max_bounds.width;
547                         new->angband.fontascent = new->angband.fnt->ascent;
548                 }
549         }
550
551         /* Check all colors, if one or more has changed the redo all GC's */
552         for (n = 0; n < NUM_COLORS; n++)
553                 if (current->angband.color[n] != new->angband.color[n])
554                         color_changed = TRUE;
555
556         /* Change all GC's if color or font has changed */
557         if (color_changed || font_changed)
558         {
559                 gcv.font = new->angband.fnt->fid;
560                 gcv.graphics_exposures = FALSE;
561                 gcv.background = new->angband.color[0];
562
563                 /* Do all GC's */
564                 for (n = 0; n < NUM_COLORS; n++)
565                 {
566                         if (depth == 1 && n >= 1)
567                                 gcv.foreground = new->angband.color[1];
568                         else
569                                 gcv.foreground = new->angband.color[n];
570                         /* Release the old GC */
571                         XtReleaseGC((Widget)current, current->angband.gc[n]);
572                         /* Get the new GC */
573                         new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
574                                                      GCBackground | GCGraphicsExposures,
575                                                      &gcv);
576                 }
577
578                 /* Replace the old XOR/highlighting GC */
579                 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
580                 WhitePixelOfScreen(XtScreen((Widget)new));
581                 gcv.function = GXxor;
582                 XtReleaseGC((Widget)current, current->angband.gc[NUM_COLORS]);
583                 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
584                                                       GCGraphicsExposures |
585                                                       GCForeground, &gcv);
586                 /* Fix the background color */
587                 new->core.background_pixel = new->angband.color[0];
588         }
589
590         /* Check if internal border width has changed, used later */
591         if (current->angband.internal_border != new->angband.internal_border)
592                 border_changed = TRUE;
593
594
595         /* If the font or the internal border has changed, all geometry
596         has to be recalculated */
597         if (font_changed || border_changed)
598         {
599                 /* Change window size */
600                 height = (current->core.height - 2 * current->angband.internal_border) /
601                 current->angband.fontheight * new->angband.fontheight +
602                 2 * current->angband.internal_border;
603                 width = (current->core.width -  2 * current->angband.internal_border) /
604                 current->angband.fontwidth * new->angband.fontwidth +
605                 2 * new->angband.internal_border;
606
607                 /* Get the new width */
608                 if (XtMakeResizeRequest((Widget)new, width, height, NULL, NULL) ==
609                     XtGeometryNo)
610                 {
611                         /* Not allowed */
612                         XtWarning("Size change denied!");
613                 }
614                 else
615                 {
616                         /* Recalculate size hints */
617                         calculateSizeHints(new);
618                 }
619         }
620
621         /* Tell it to redraw the widget if anything has changed */
622         return (font_changed || color_changed || border_changed);
623 }
624
625 /*
626  * Calculate size hints
627  */
628 static void calculateSizeHints(AngbandWidget new)
629 {
630         TopLevelShellWidget parent =
631         (TopLevelShellWidget)XtParent((Widget) new);
632
633         /* Calculate minimum size */
634         parent->wm.size_hints.min_height =
635         new->angband.min_rows * new->angband.fontheight +
636         2 * new->angband.internal_border;
637         parent->wm.size_hints.min_width =
638         new->angband.min_columns * new->angband.fontwidth +
639         2 * new->angband.internal_border;
640         parent->wm.size_hints.flags |= PMinSize;
641
642         /* Calculate maximum size */
643         parent->wm.size_hints.max_height =
644         new->angband.max_rows * new->angband.fontheight +
645         2 * new->angband.internal_border;
646         parent->wm.size_hints.max_width =
647         new->angband.max_columns * new->angband.fontwidth +
648         2 * new->angband.internal_border;
649         parent->wm.size_hints.flags |= PMaxSize;
650
651         /* Calculate increment size */
652         parent->wm.size_hints.height_inc = new->angband.fontheight;
653         parent->wm.size_hints.width_inc = new->angband.fontwidth;
654         parent->wm.size_hints.flags |= PResizeInc;
655
656         /* Calculate base size */
657         parent->wm.base_height = 2 * new->angband.internal_border;
658         parent->wm.base_width = 2 * new->angband.internal_border;
659         parent->wm.size_hints.flags |= PBaseSize;
660 }
661
662 /*
663  * Load a font
664  */
665 static XFontStruct *getFont(AngbandWidget widget,
666                             String font, Boolean fallback)
667 {
668         Display *dpy = XtDisplay((Widget) widget);
669         char buf[256];
670         XFontStruct *fnt = NULL;
671
672         if (!(fnt = XLoadQueryFont(dpy, font)) && fallback)
673         {
674                 sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
675                 XtWarning(buf);
676                 if (!(fnt = XLoadQueryFont(dpy, "fixed")))
677                         XtError("Can't fint the font \"fixed\"!, bailing out\n");
678         }
679
680         return fnt;
681 }
682
683
684
685 /*** The non-widget code ****/
686
687 #ifndef IsModifierKey
688
689 /*
690  * Keysym macros, used on Keysyms to test for classes of symbols
691  * These were stolen from one of the X11 header files
692  */
693
694 #define IsKeypadKey(keysym) \
695   (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
696
697 #define IsCursorKey(keysym) \
698   (((unsigned)(keysym) >= XK_Home)     && ((unsigned)(keysym) <  XK_Select))
699
700 #define IsPFKey(keysym) \
701   (((unsigned)(keysym) >= XK_KP_F1)     && ((unsigned)(keysym) <= XK_KP_F4))
702
703 #define IsFunctionKey(keysym) \
704   (((unsigned)(keysym) >= XK_F1)       && ((unsigned)(keysym) <= XK_F35))
705
706 #define IsMiscFunctionKey(keysym) \
707   (((unsigned)(keysym) >= XK_Select)   && ((unsigned)(keysym) <  XK_KP_Space))
708
709 #define IsModifierKey(keysym) \
710   (((unsigned)(keysym) >= XK_Shift_L)  && ((unsigned)(keysym) <= XK_Hyper_R))
711
712 #endif
713
714
715 /*
716  * Checks if the keysym is a special key or a normal key
717  * Assume that XK_MISCELLANY keysyms are special
718  */
719 #define IsSpecialKey(keysym) \
720   ((unsigned)(keysym) >= 0xFF00)
721
722
723
724 /*
725  * Maximum number of windows XXX XXX XXX XXX
726  */
727 #define MAX_TERM_DATA 8
728
729 /*
730  * Number of fallback resources per window
731  */
732 #define TERM_FALLBACKS 6
733
734 /*
735  * Number of windows with special fallback resources
736  */
737 #define SPECIAL_FALLBACKS 3
738
739 /*
740  * Forward declare
741  */
742 typedef struct term_data term_data;
743
744 /*
745  * A structure for each "term"
746  */
747 struct term_data
748 {
749         term t;
750
751         AngbandWidget widget;
752 };
753
754 /*
755  * An array of term_data's
756  */
757 static term_data data[MAX_TERM_DATA];
758
759 char *termNames[MAX_TERM_DATA] =
760 {
761     "angband",
762     "mirror",
763     "recall",
764     "choice",
765     "term-4",
766     "term-5",
767     "term-6",
768     "term-7"
769 };
770
771 Arg specialArgs[TERM_FALLBACKS][SPECIAL_FALLBACKS] =
772 {
773     /* The main screen */
774     {
775         { XtNstartRows,    24},
776         { XtNstartColumns, 80},
777         { XtNminRows,      24},
778         { XtNminColumns,   80},
779         { XtNmaxRows,      24},
780         { XtNmaxColumns,   80}
781     },
782
783     /* The "mirror" window */
784     {
785         { XtNstartRows,    24},
786         { XtNstartColumns, 80},
787         { XtNminRows,      1},
788         { XtNminColumns,   1},
789         { XtNmaxRows,      24},
790         { XtNmaxColumns,   80}
791     },
792
793     /* The "recall" window */
794     {
795         { XtNstartRows,    8},
796         { XtNstartColumns, 80},
797         { XtNminRows,      1},
798         { XtNminColumns,   1},
799         { XtNmaxRows,      24},
800         { XtNmaxColumns,   80}
801     }
802 };
803
804 Arg defaultArgs[TERM_FALLBACKS] =
805 {
806         { XtNstartRows,    24},
807         { XtNstartColumns, 80},
808         { XtNminRows,      1},
809         { XtNminColumns,   1},
810         { XtNmaxRows,      24},
811         { XtNmaxColumns,   80}
812 };
813
814
815 /*
816  * The application context
817  */
818 XtAppContext appcon;
819
820 /*
821  * User changable information about widgets
822  */
823 static String fallback[] =
824 {
825         "Angband.angband.iconName:            Angband",
826         "Angband.angband.title:               Angband",
827         "Angband.mirror.iconName:             Mirror",
828         "Angband.mirror.title:                Mirror",
829         "Angband.recall.iconName:             Recall",
830         "Angband.recall.title:                Recall",
831         "Angband.choice.iconName:             Choice",
832         "Angband.choice.title:                Choice",
833         "Angband.term-4.iconName:             Term 4",
834         "Angband.term-4.title:                Term 4",
835         "Angband.term-5.iconName:             Term 5",
836         "Angband.term-5.title:                Term 5",
837         "Angband.term-6.iconName:             Term 6",
838         "Angband.term-6.title:                Term 6",
839         "Angband.term-7.iconName:             Term 7",
840         "Angband.term-7.title:                Term 7",
841         NULL
842 };
843
844
845
846 /*
847  * Do a redraw
848  */
849 static void react_redraw(Widget widget,
850                          XtPointer client_data, XtPointer call_data)
851 {
852         term_data *old_td = (term_data*)(Term->data);
853         term_data *td = (term_data*)client_data;
854
855         /* Activate the proper Term */
856         Term_activate(&td->t);
857
858         /* Request a redraw */
859         Term_redraw();
860
861         /* Activate the old Term */
862         Term_activate(&old_td->t);
863 }
864
865 /*
866  * Process a keypress event
867  */
868 static void react_keypress(XKeyEvent *ev)
869 {
870         int i, n, mc, ms, mo, mx;
871
872         KeySym ks;
873
874         char buf[128];
875         char msg[128];
876
877
878         /* Check for "normal" keypresses */
879         n = XLookupString(ev, buf, 125, &ks, NULL);
880
881         /* Terminate */
882         buf[n] = '\0';
883
884         /* Extract four "modifier flags" */
885         mc = (ev->state & ControlMask) ? TRUE : FALSE;
886         ms = (ev->state & ShiftMask) ? TRUE : FALSE;
887         mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
888         mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
889
890         /* Hack -- Ignore "modifier keys" */
891         if (IsModifierKey(ks)) return;
892
893         /* Normal keys with no modifiers */
894         if (n && !mo && !mx && !IsSpecialKey(ks))
895         {
896                 /* Enqueue the normal key(s) */
897                 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
898
899                 /* All done */
900                 return;
901         }
902
903         /* Handle a few standard keys */
904         switch (ks)
905         {
906                 case XK_Escape:
907                 Term_keypress(ESCAPE); return;
908
909                 case XK_Return:
910                 Term_keypress('\r'); return;
911
912                 case XK_Tab:
913                 Term_keypress('\t'); return;
914
915                 case XK_Delete:
916                 case XK_BackSpace:
917                 Term_keypress('\010'); return;
918         }
919
920         /* Hack -- Use the KeySym */
921         if (ks)
922         {
923                 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
924                         mc ? "N" : "", ms ? "S" : "",
925                         mo ? "O" : "", mx ? "M" : "",
926                         (unsigned long)(ks), 13);
927         }
928
929         /* Hack -- Use the Keycode */
930         else
931         {
932                 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
933                         mc ? "N" : "", ms ? "S" : "",
934                         mo ? "O" : "", mx ? "M" : "",
935                         ev->keycode, 13);
936         }
937
938         /* Enqueue the "fake" string */
939         for (i = 0; msg[i]; i++)
940                 Term_keypress(msg[i]);
941
942         /* Hack -- dump an "extra" string */
943         if (n)
944         {
945                 /* Start the "extra" string */
946                 Term_keypress(28);
947
948                 /* Enqueue the "real" string */
949                 for (i = 0; buf[i]; i++)
950                         Term_keypress(buf[i]);
951
952                 /* End the "extra" string */
953                 Term_keypress(28);
954         }
955 }
956
957
958 static void handle_event (Widget widget, XtPointer client_data, XEvent *event,
959                           Boolean *continue_to_dispatch)
960 {
961         term_data *old_td = (term_data*)(Term->data);
962         term_data *td = (term_data *)client_data;
963
964         /* Continue to process the event by default */
965         *continue_to_dispatch = TRUE;
966
967         /* Activate the Term */
968         Term_activate(&td->t);
969
970         switch (event->type)
971         {
972                 case KeyPress:
973                 react_keypress(&(event->xkey));
974                 *continue_to_dispatch = FALSE; /* We took care of the event */
975                 break;
976
977                 default:
978                 break;  /* Huh? Shouldn't happen! */
979         }
980
981         /* Activate the old term */
982         Term_activate(&old_td->t);
983
984         return;
985 }
986
987
988 /*
989  * Process an event (or just check for one)
990  */
991 errr CheckEvent(bool wait)
992 {
993         XEvent event;
994
995         /* No events ready, and told to just check */
996         if (!wait && !XtAppPending(appcon)) return 1;
997
998         /* Process */
999         while (1)
1000         {
1001                 XtAppNextEvent(appcon, &event);
1002                 XtDispatchEvent(&event);
1003                 if (!XtAppPending(appcon)) break;
1004         }
1005
1006         return (0);
1007 }
1008
1009
1010 /*
1011  * Handle a "special request"
1012  */
1013 static errr Term_xtra_xaw(int n, int v)
1014 {
1015         int i;
1016
1017         /* Handle a subset of the legal requests */
1018         switch (n)
1019         {
1020                 /* Make a noise */
1021                 case TERM_XTRA_NOISE:
1022                 XBell(XtDisplay((Widget)data[0].widget), 100);
1023                 return (0);
1024
1025                 /* Flush the output */
1026                 case TERM_XTRA_FRESH:
1027                 XFlush(XtDisplay((Widget)data[0].widget));
1028                 /* Nonblock event-check so the flushed events can be showed */
1029                 CheckEvent(FALSE);
1030                 return (0);
1031
1032                 /* Process random events */
1033                 case TERM_XTRA_BORED:
1034                 return (CheckEvent(0));
1035
1036                 /* Process events */
1037                 case TERM_XTRA_EVENT:
1038                 return (CheckEvent(v));
1039
1040                 /* Flush events */
1041                 case TERM_XTRA_FLUSH:
1042                 while (!CheckEvent(FALSE));
1043                 return (0);
1044
1045                 /* Delay */
1046                 case TERM_XTRA_DELAY:
1047                 usleep(1000 * v);
1048                 return (0);
1049
1050                 /* Clear the window */
1051                 case TERM_XTRA_CLEAR:
1052                 for (i=0; i<MAX_TERM_DATA; i++) {
1053                     if (Term == &data[i].t)
1054                         XClearWindow(XtDisplay((Widget)data[i].widget),
1055                                      XtWindow((Widget)data[i].widget));
1056                 }
1057                 return (0);
1058         }
1059
1060         /* Unknown */
1061         return (1);
1062 }
1063
1064
1065
1066 /*
1067  * Erase a number of characters
1068  */
1069 static errr Term_wipe_xaw(int x, int y, int n)
1070 {
1071         term_data *td = (term_data*)(Term->data);
1072
1073         /* Erase using color 0 */
1074         AngbandClearArea(td->widget, x, y, n, 1, 0);
1075
1076         /* Success */
1077         return (0);
1078 }
1079
1080
1081
1082 /*
1083  * Draw the cursor (XXX by hiliting)
1084  */
1085 static errr Term_curs_xaw(int x, int y)
1086 {
1087         term_data *td = (term_data*)(Term->data);
1088
1089         /* Hilite the cursor character */
1090         AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
1091
1092         /* Success */
1093         return (0);
1094 }
1095
1096
1097 /*
1098  * Draw a number of characters
1099  */
1100 static errr Term_text_xaw(int x, int y, int n, byte a, concptr s)
1101 {
1102         term_data *td = (term_data*)(Term->data);
1103
1104         /* Draw the text */
1105         AngbandOutputText(td->widget, x, y, (String)s, n, (a & 0x0F));
1106
1107         /* Success */
1108         return (0);
1109 }
1110
1111
1112 /*
1113  * Raise a term
1114  */
1115 static void term_raise(term_data win)
1116 {
1117         Widget widget = (Widget)win.widget;
1118
1119         XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
1120 }
1121
1122
1123 /*
1124  * Initialize a term_data
1125  */
1126 static errr term_data_init(term_data *td, Widget topLevel,
1127                            int key_buf, String name,
1128                            ArgList widget_arg, Cardinal widget_arg_no)
1129 {
1130         Widget parent;
1131         term *t = &td->t;
1132
1133         /* Create the shell widget */
1134         parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel,
1135                                     NULL, 0);
1136
1137         /* Create the interior widget */
1138         td->widget = (AngbandWidget)
1139         XtCreateManagedWidget (name, angbandWidgetClass,
1140                                parent, widget_arg, widget_arg_no);
1141
1142         /* Initialize the term (full size) */
1143         term_init(t, 80, 24, key_buf);
1144
1145         /* Use a "soft" cursor */
1146         t->soft_cursor = TRUE;
1147
1148         /* Erase with "white space" */
1149         t->attr_blank = TERM_WHITE;
1150         t->char_blank = ' ';
1151
1152         /* Hooks */
1153         t->xtra_hook = Term_xtra_xaw;
1154         t->curs_hook = Term_curs_xaw;
1155         t->wipe_hook = Term_wipe_xaw;
1156         t->text_hook = Term_text_xaw;
1157
1158         /* Save the data */
1159         t->data = td;
1160
1161         /* Register the keypress event handler */
1162         XtAddEventHandler((Widget)td->widget, KeyPressMask,
1163                           False, (XtEventHandler) handle_event, td);
1164
1165         /* Redraw callback */
1166         XtAddCallback((Widget)td->widget, XtNredrawCallback,
1167                       react_redraw, td);
1168
1169         /* Realize the widget */
1170         XtRealizeWidget(parent);
1171
1172         /* Make it visible */
1173         XtPopup(parent, XtGrabNone);
1174
1175         /* Activate (important) */
1176         Term_activate(t);
1177
1178         return 0;
1179 }
1180
1181
1182 /*
1183  * Initialization function for an X Athena Widget module to Angband
1184  *
1185  * Mega-Hack -- we are not given the actual "argc" and "argv" from
1186  * the main program, so we fake one.  Thus, we are unable to parse
1187  * any "display" requests for external devices.  This is okay, since
1188  * we need to verify the display anyway, to work with "main.c".
1189  */
1190 errr init_xaw(void)
1191 {
1192         int argc, i;
1193         char *argv[2];
1194         Widget topLevel;
1195         Display *dpy;
1196
1197
1198         /* One fake argument */
1199         argc = 1;
1200
1201         /* Save the program name */
1202         argv[0] = argv0;
1203
1204         /* Terminate */
1205         argv[1] = NULL;
1206
1207
1208         /* Attempt to open the local display */
1209         dpy = XOpenDisplay("");
1210
1211         /* Failure -- assume no X11 available */
1212         if (!dpy) return (-1);
1213
1214         /* Close the local display */
1215         XCloseDisplay(dpy);
1216
1217
1218 #ifdef USE_XAW_LANG
1219         /* Support locale processing */
1220         XtSetLanguageProc(NULL, NULL, NULL);
1221 #endif
1222
1223         /* Initialize the toolkit */
1224         topLevel = XtAppInitialize (&appcon, "Angband", NULL, 0, &argc, argv,
1225                                     fallback, NULL, 0);
1226
1227         /* Initialize the windows */
1228         for (i=0; i<MAX_TERM_DATA; i++) {
1229             term_data_init (&data[i], topLevel, 1024, termNames[i],
1230                             i<SPECIAL_FALLBACKS ? specialArgs[i] : defaultArgs,
1231                             TERM_FALLBACKS);
1232             angband_term[i] = Term;
1233         }
1234
1235         /* Activate the "Angband" window screen */
1236         Term_activate(&data[0].t);
1237
1238         /* Raise the "Angband" window */
1239         term_raise(data[0]);
1240
1241         /* Success */
1242         return (0);
1243 }
1244
1245 #endif
1246