1 /* File: main-xaw.c */
2
3 /* Purpose: Support for X Athena Widget based Angband */
4 /* Most code written by Torbj�rn Lindgren (tl@cd.chalmers.se) */
5
6 #include "angband.h"
7
8 #ifdef USE_XAW
9
10 #ifndef __MAKEDEPEND__
11 #include <X11/Xlib.h>
12 #include <X11/StringDefs.h>
13 #include <X11/Xutil.h>
14 #include <X11/Intrinsic.h>
15 #include <X11/Shell.h>
16 #include <X11/keysym.h>
17 #include <X11/keysymdef.h>
18 #include <X11/IntrinsicP.h>
19 #include <X11/CoreP.h>
20 #include <X11/ShellP.h>
21 #include <X11/StringDefs.h>
22 #include <X11/Xaw/SimpleP.h>
23 #include <X11/Xaw/Simple.h>
24 #include <X11/Xaw/XawInit.h>
25 #endif /* __MAKEDEPEND__ */
26
27
28 /*
29 * OPTION: Allow the use of a "Recall Window", if supported
30 */
31 #define GRAPHIC_RECALL
32
33 /*
34 * OPTION: Allow the use of a "Choice Window", if supported
35 */
36 #define GRAPHIC_CHOICE
37
38 /*
39 * OPTION: Allow the use of a "Mirror Window", if supported
40 */
41 #define GRAPHIC_MIRROR
42
43
44 /*****************************************************
45 *
46 * Resource description
47 *
48 *****************************************************/
49
50 /* Resources:
51
52 Name Class RepType Default Value
53 ---- ----- ------- -------------
54 background Background Pixel XtDefaultBackground
55 border BorderColor Pixel XtDefaultForeground
56 borderWidth BorderWidth Dimension 1
57 cursor Cursor Cursor None
58 cursorName Cursor String NULL
59 destroyCallback Callback Pointer NULL
60 height Height Dimension 0
61 insensitiveBorder Insensitive Pixmap Gray
62 mappedWhenManaged MappedWhenManaged Boolean True
63 pointerColor Foreground Pixel XtDefaultForeground
64 pointerColorBackground Background Pixel XtDefaultBackground
65 sensitive Sensitive Boolean True
66 width Width Dimension 0
67 x Position Position 0
68 y Position Position 0
69
70 */
71
72 /*
73
74 My own X Resources look like this (on a 1152x900 screen):
75
76 angband*angband*font: 12x24
77 angband*angband*geometry: +0+-20
78 angband*recall*font: 7x13
79 angband*recall*geometry: 80x10+0+586
80 angband*choice*font: 7x13
81 angband*choice*geometry: -0-0
82
83 It's also possible to change the colors using X Resources, the
84 standard colors would look like:
85
86 angband*color0: #000000
87 angband*color1: #ffffff
88 angband*color2: #a6a6a6
89 angband*color3: #ff6302
90 angband*color4: #ca0808
91 angband*color5: #008e18
92 angband*color6: #0000e3
93 angband*color7: #814007
94 angband*color8: #6b6b6b
95 angband*color9: #d6d6d6
96 angband*color10: #5100c2
97 angband*color11: #fdf105
98 angband*color12: #ff9259
99 angband*color13: #26cf17
100 angband*color14: #02b2f2
101 angband*color15: #b28b48
102
103 And the newer colors look like:
104
105 angband*color0: #000000
106 angband*color1: #ffffff
107 angband*color2: #d7d7d7
108 angband*color3: #ff9200
109 angband*color4: #ff0000
110 angband*color5: #00cd00
111 angband*color6: #0000fe
112 angband*color7: #c86400
113 angband*color8: #a3a3a3
114 angband*color9: #ebebeb
115 angband*color10: #a500ff
116 angband*color11: #fffd00
117 angband*color12: #ff00bc
118 angband*color13: #00ff00
119 angband*color14: #00c8ff
120 angband*color15: #ffcc80
121
122 Some older monochrome monitors have problem with white text on black
123 background. The new code can handle the reverse situation if the user
124 wants/needs this.
125
126 The following X Resources gives black text on white background using
127 Angband/Xaw. The other colors (2-15) isn't changed, since they're not
128 used on a monochrome monitor.
129
130 angband*color0: #ffffff
131 angband*color1: #000000
132
133 */
134
135 /* New resource names */
136 #define XtNstartRows "startRows"
137 #define XtNstartColumns "startColumns"
138 #define XtNminRows "minRows"
139 #define XtNminColumns "minColumns"
140 #define XtNmaxRows "maxRows"
141 #define XtNmaxColumns "maxColumns"
142 #define XtNinternalBorder "internalBorder"
143 #define XtNcolor0 "color0"
144 #define XtNcolor1 "color1"
145 #define XtNcolor2 "color2"
146 #define XtNcolor3 "color3"
147 #define XtNcolor4 "color4"
148 #define XtNcolor5 "color5"
149 #define XtNcolor6 "color6"
150 #define XtNcolor7 "color7"
151 #define XtNcolor8 "color8"
152 #define XtNcolor9 "color9"
153 #define XtNcolor10 "color10"
154 #define XtNcolor11 "color11"
155 #define XtNcolor12 "color12"
156 #define XtNcolor13 "color13"
157 #define XtNcolor14 "color14"
158 #define XtNcolor15 "color15"
159 #define XtNredrawCallback "redrawCallback"
160
161 /* External definitions */
162 #define COLOR_XOR 16
163 #define NUM_COLORS 16
164
165 /* C Widget type definition */
166
167 typedef struct AngbandRec *AngbandWidget;
168
169 /* C Widget class type definition */
170
171 typedef struct AngbandClassRec *AngbandWidgetClass;
172
173
174 /*
175 * New fields for the Angband widget record
176 */
177
178 typedef struct
179 {
180 /* Settable resources */
181 int start_rows;
182 int start_columns;
183 int min_rows;
184 int min_columns;
185 int max_rows;
186 int max_columns;
187 int internal_border;
188 String font;
189 Pixel color[NUM_COLORS];
190 XtCallbackList redraw_callbacks;
191
192 /* Private state */
193 XFontStruct *fnt;
194 Dimension fontheight;
195 Dimension fontwidth;
196 Dimension fontascent;
197 GC gc[NUM_COLORS+1]; /* Includes a special 'xor' color */
198
199 } AngbandPart;
200
201
202 /*
203 * Full instance record declaration
204 */
205
206 typedef struct AngbandRec AngbandRec;
207
208 struct AngbandRec
209 {
210 CorePart core;
211 SimplePart simple;
212 AngbandPart angband;
213 };
214
215
216 /*
217 * New fields for the Angband widget class record
218 */
219
220 typedef struct AngbandClassPart AngbandClassPart;
221
222 struct AngbandClassPart
223 {
224 int dummy;
225 };
226
227
228 /*
229 * Full class record declaration
230 */
231
232 typedef struct AngbandClassRec AngbandClassRec;
233
234 struct AngbandClassRec
235 {
236 CoreClassPart core_class;
237 SimpleClassPart simple_class;
238 AngbandClassPart angband_class;
239 };
240
241
242
243 /* Angband widget, Created by Torbj�rn Lindgren (tl@cd.chalmers.se) */
244
245 /*
246 * Note that it isn't as self-contained as it really should be,
247 * originally everything was output to a Pixmap which was later copied
248 * to the screen when necessary. I had to abandon that idea since
249 * Pixmaps creates big performance problems for some really old X
250 * terminals (such as 3/50's running Xkernel).
251 */
252
253
254 /*
255 * The default colors used is based on the ones used in main-mac.c.
256 * The main difference is that they are gamma corrected for a gamma of
257 * 1.6. MacOS do gamma correction afterwards, but X uses raw
258 * colors. The Gamma of most color screens are about 1.5 - 1.7.
259 * Color 12 was later changed a bit so that it didn't look as similar
260 * to color 3/4.
261 */
262
263 #define offset(field) XtOffsetOf(AngbandRec, angband.field)
264
265 /*
266 * Fallback resources for Angband widget
267 */
268 static XtResource resources[] =
269 {
270 { XtNstartRows, XtCValue, XtRInt, sizeof(int),
271 offset(start_rows), XtRImmediate, (XtPointer) 24 },
272 { XtNstartColumns, XtCValue, XtRInt, sizeof(int),
273 offset(start_columns), XtRImmediate, (XtPointer) 80 },
274 { XtNminRows, XtCValue, XtRInt, sizeof(int),
275 offset(min_rows), XtRImmediate, (XtPointer) 1 },
276 { XtNminColumns, XtCValue, XtRInt, sizeof(int),
277 offset(min_columns), XtRImmediate, (XtPointer) 1 },
278 { XtNmaxRows, XtCValue, XtRInt, sizeof(int),
279 offset(max_rows), XtRImmediate, (XtPointer) 24 },
280 { XtNmaxColumns, XtCValue, XtRInt, sizeof(int),
281 offset(max_columns), XtRImmediate, (XtPointer) 80 },
282 { XtNinternalBorder, XtCValue, XtRInt, sizeof(int),
283 offset(internal_border), XtRImmediate, (XtPointer) 2 },
284 { XtNfont, XtCFont, XtRString, sizeof(char *),
285 offset(font), XtRString, "9x15" },
286 { XtNcolor0, XtCColor, XtRPixel, sizeof(Pixel),
287 offset(color[0]), XtRString, "black" },
288 { XtNcolor1, XtCColor, XtRPixel, sizeof(Pixel),
289 offset(color[1]), XtRString, "white" },
290 { XtNcolor2, XtCColor, XtRPixel, sizeof(Pixel),
291 offset(color[2]), XtRString, "#d7d7d7" },
292 { XtNcolor3, XtCColor, XtRPixel, sizeof(Pixel),
293 offset(color[3]), XtRString, "#ff9200" },
294 { XtNcolor4, XtCColor, XtRPixel, sizeof(Pixel),
295 offset(color[4]), XtRString, "#ff0000" },
296 { XtNcolor5, XtCColor, XtRPixel, sizeof(Pixel),
297 offset(color[5]), XtRString, "#00cd00" },
298 { XtNcolor6, XtCColor, XtRPixel, sizeof(Pixel),
299 offset(color[6]), XtRString, "#0000fe" },
300 { XtNcolor7, XtCColor, XtRPixel, sizeof(Pixel),
301 offset(color[7]), XtRString, "#c86400" },
302 { XtNcolor8, XtCColor, XtRPixel, sizeof(Pixel),
303 offset(color[8]), XtRString, "#a3a3a3" },
304 { XtNcolor9, XtCColor, XtRPixel, sizeof(Pixel),
305 offset(color[9]), XtRString, "#ebebeb" },
306 { XtNcolor10, XtCColor, XtRPixel, sizeof(Pixel),
307 offset(color[10]), XtRString, "#a500ff" },
308 { XtNcolor11, XtCColor, XtRPixel, sizeof(Pixel),
309 offset(color[11]), XtRString, "#fffd00" },
310 { XtNcolor12, XtCColor, XtRPixel, sizeof(Pixel),
311 offset(color[12]), XtRString, "#ff00bc" },
312 { XtNcolor13, XtCColor, XtRPixel, sizeof(Pixel),
313 offset(color[13]), XtRString, "#00ff00" },
314 { XtNcolor14, XtCColor, XtRPixel, sizeof(Pixel),
315 offset(color[14]), XtRString, "#00c8ff" },
316 { XtNcolor15, XtCColor, XtRPixel, sizeof(Pixel),
317 offset(color[15]), XtRString, "#ffcc80" },
318
319 #if 0
320
321 { XtNcolor2, XtCColor, XtRPixel, sizeof(Pixel),
322 offset(color[2]), XtRString, "#a6a6a6" },
323 { XtNcolor3, XtCColor, XtRPixel, sizeof(Pixel),
324 offset(color[3]), XtRString, "#ff6302" },
325 { XtNcolor4, XtCColor, XtRPixel, sizeof(Pixel),
326 offset(color[4]), XtRString, "#ca0808" },
327 { XtNcolor5, XtCColor, XtRPixel, sizeof(Pixel),
328 offset(color[5]), XtRString, "#008e18" },
329 { XtNcolor6, XtCColor, XtRPixel, sizeof(Pixel),
330 offset(color[6]), XtRString, "#0000e3" },
331 { XtNcolor7, XtCColor, XtRPixel, sizeof(Pixel),
332 offset(color[7]), XtRString, "#814007" },
333 { XtNcolor8, XtCColor, XtRPixel, sizeof(Pixel),
334 offset(color[8]), XtRString, "#6b6b6b" },
335 { XtNcolor9, XtCColor, XtRPixel, sizeof(Pixel),
336 offset(color[9]), XtRString, "#d6d6d6" },
337 { XtNcolor10, XtCColor, XtRPixel, sizeof(Pixel),
338 offset(color[10]), XtRString, "#5100c2" },
339 { XtNcolor11, XtCColor, XtRPixel, sizeof(Pixel),
340 offset(color[11]), XtRString, "#fdf105" },
341 { XtNcolor12, XtCColor, XtRPixel, sizeof(Pixel),
342 offset(color[12]), XtRString, "#ff9259" },
343 { XtNcolor13, XtCColor, XtRPixel, sizeof(Pixel),
344 offset(color[13]), XtRString, "#26cf17" },
345 { XtNcolor14, XtCColor, XtRPixel, sizeof(Pixel),
346 offset(color[14]), XtRString, "#02b2f2" },
347 { XtNcolor15, XtCColor, XtRPixel, sizeof(Pixel),
348 offset(color[15]), XtRString, "#b28b48" },
349
350 #endif
351
352 { XtNredrawCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
353 offset(redraw_callbacks), XtRCallback, (XtPointer)NULL }
354 };
355
356 #undef offset
357
358 /* Forward declarations for Widget functions */
359 static void Initialize(AngbandWidget request, AngbandWidget new);
360 static void Redisplay(AngbandWidget w, XEvent *event, Region region);
361 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
362 AngbandWidget new, ArgList args, Cardinal *num_args);
363 static void Destroy(AngbandWidget widget);
364
365 /* Forward declaration for internal functions */
366 static void calculateSizeHints(AngbandWidget new);
367 static XFontStruct *getFont(AngbandWidget widget,
368 String font, Boolean fallback);
369
370
371 /* Class record constanst */
372 AngbandClassRec angbandClassRec =
373 {
374 {
375 /* Core class fields initialization */
376 #define superclass (&simpleClassRec)
377 /* superclass */ (WidgetClass) superclass,
378 /* class_name */ "Angband",
379 /* widget_size */ sizeof(AngbandRec),
380 /* class_initialize */ NULL,
381 /* class_part_initialize*/ NULL,
382 /* class_inited */ FALSE,
383 /* initialize */ (XtInitProc) Initialize,
384 /* initialize_hook */ NULL,
385 /* realize */ XtInheritRealize,
386 /* actions */ NULL,
387 /* num_actions */ 0,
388 /* resources */ resources,
389 /* num_resources */ XtNumber(resources),
390 /* xrm_class */ NULLQUARK,
391 /* compress_motion */ TRUE,
392 /* compress_exposure */ XtExposeCompressMultiple,
393 /* compress_enterleave */ TRUE,
394 /* visible_interest */ FALSE,
395 /* destroy */ (XtWidgetProc) Destroy,
396 /* resize */ NULL,
397 /* expose */ (XtExposeProc) Redisplay,
398 /* set_values */ (XtSetValuesFunc) SetValues,
399 /* set_values_hook */ NULL,
400 /* set_values_almost */ XtInheritSetValuesAlmost,
401 /* get_values_hook */ NULL,
402 /* accept_focus */ NULL,
403 /* version */ XtVersion,
404 /* callback_private */ NULL,
405 /* tm_table */ NULL,
406 /* query_geometry */ NULL,
407 /* display_accelerator */ XtInheritDisplayAccelerator,
408 /* extension */ NULL
409 },
410 /* Simple class fields initialization */
411 {
412 /* change_sensitive */ XtInheritChangeSensitive
413 },
414 /* Angband class fields initialization */
415 {
416 /* nothing */ 0
417 }
418 };
419
420 /* Class record pointer */
421 WidgetClass angbandWidgetClass = (WidgetClass) &angbandClassRec;
422
423
424 /*
425 * Public procedures
426 */
AngbandOutputText(AngbandWidget widget,int x,int y,String txt,int len,int color)427 static void AngbandOutputText(AngbandWidget widget, int x, int y,
428 String txt, int len, int color)
429 {
430 /* Do nothing if the string is null */
431 if (!txt || !*txt)
432 return;
433
434 /* Check the lenght, and fix it if it's below zero */
435 if (len < 0)
436 len = strlen(txt);
437
438 /* Figure out where to place the text */
439 y = y * widget->angband.fontheight + widget->angband.fontascent +
440 widget->angband.internal_border;
441 x = x * widget->angband.fontwidth + widget->angband.internal_border;
442
443 /* Place the string */
444 XDrawImageString (XtDisplay(widget), XtWindow(widget),
445 widget->angband.gc[color], x, y, txt, len);
446 }
447
AngbandClearArea(AngbandWidget widget,int x,int y,int w,int h,int color)448 static void AngbandClearArea(AngbandWidget widget,
449 int x, int y, int w, int h, int color)
450 {
451 /* Figure out which area to clear */
452 y = y * widget->angband.fontheight + widget->angband.internal_border;
453 x = x * widget->angband.fontwidth + widget->angband.internal_border;
454
455 /* Clear the area */
456 XFillRectangle(XtDisplay(widget), XtWindow(widget),
457 widget->angband.gc[color],
458 x, y, widget->angband.fontwidth*w,
459 widget->angband.fontheight*h);
460 }
461
462 /*
463 * Private procedures
464 */
465
466 /*
467 * Procedure Initialize() is called during the widget creation
468 * process. Initialize() load fonts and calculates window geometry.
469 * The request parameter is filled in by parents to this widget. The
470 * new parameter is the request parameter plus data filled in by this
471 * widget. All changes should be done to the new parameter.
472 */
Initialize(AngbandWidget request,AngbandWidget new)473 static void Initialize(AngbandWidget request, AngbandWidget new)
474 {
475 XGCValues gcv;
476 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
477 TopLevelShellWidget parent =
478 (TopLevelShellWidget)XtParent((Widget) new);
479 int n;
480
481 /* Fix the background color */
482 new->core.background_pixel = new->angband.color[0];
483
484 /* Get some information about the font */
485 new->angband.fnt = getFont(new, new->angband.font, TRUE);
486 new->angband.fontheight = new->angband.fnt->ascent +
487 new->angband.fnt->descent;
488 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
489 new->angband.fontascent = new->angband.fnt->ascent;
490
491 /* Create and initialize the graphics contexts */ /* GXset? */
492 gcv.font = new->angband.fnt->fid;
493 gcv.graphics_exposures = FALSE;
494 gcv.background = new->angband.color[0];
495 for (n = 0; n < NUM_COLORS; n++)
496 {
497 if (depth == 1 && n >= 1)
498 gcv.foreground = new->angband.color[1];
499 else
500 gcv.foreground = new->angband.color[n];
501 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
502 GCBackground | GCGraphicsExposures,
503 &gcv);
504 }
505
506 /* Create a special GC for highlighting */
507 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
508 WhitePixelOfScreen(XtScreen((Widget)new));
509 gcv.function = GXxor;
510 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
511 GCGraphicsExposures |
512 GCForeground, &gcv);
513
514 /* Calculate window geometry */
515 new->core.height = new->angband.start_rows * new->angband.fontheight +
516 2 * new->angband.internal_border;
517 new->core.width = new->angband.start_columns * new->angband.fontwidth +
518 2 * new->angband.internal_border;
519
520 /* We need to be able to resize the Widget if the user want's to
521 change font on the fly! */
522 parent->shell.allow_shell_resize = TRUE;
523
524 /* Calculates all the size hints */
525 calculateSizeHints(new);
526 }
527
528 /*
529 * Procedure Destroy() is called during the destruction of the widget.
530 * Destroy() releases and frees GCs, frees the pixmaps and frees the
531 * fonts.
532 */
Destroy(AngbandWidget widget)533 static void Destroy(AngbandWidget widget)
534 {
535 int n;
536
537 /* Free all GC's */
538 for (n = 0; n < NUM_COLORS+1; n++)
539 XtReleaseGC((Widget)widget, widget->angband.gc[n]);
540
541 /* Free the font */
542 XFreeFont(XtDisplay((Widget)widget), widget->angband.fnt);
543 }
544
545 /*
546 * Procedure Redisplay() is called as the result of an Expose event.
547 * Use the redraw callback to do a full redraw
548 */
Redisplay(AngbandWidget widget,XEvent * event,Region region)549 static void Redisplay(AngbandWidget widget, XEvent *event, Region region)
550 {
551 if (XtHasCallbacks((Widget)widget, XtNredrawCallback) == XtCallbackHasSome)
552 XtCallCallbacks((Widget)widget, XtNredrawCallback, NULL);
553 }
554
555 /*
556 * Font, colors and internal_border can be changed on the fly.
557 * The entire widget is redrawn if any of those parameters change (all
558 * can potentially have effects that spans the whole widget).
559 */
SetValues(AngbandWidget current,AngbandWidget request,AngbandWidget new,ArgList args,Cardinal * num_args)560 static Boolean SetValues(AngbandWidget current, AngbandWidget request,
561 AngbandWidget new, ArgList args,
562 Cardinal *num_args)
563 {
564 int depth = DefaultDepthOfScreen(XtScreen((Widget) new));
565 Boolean font_changed = FALSE;
566 Boolean border_changed = FALSE;
567 Boolean color_changed = FALSE;
568 XGCValues gcv;
569 int height, width;
570 int n;
571
572 /* Changed font? */
573 if (current->angband.font != new->angband.font)
574 {
575 /* Check if the font exists */
576 new->angband.fnt = getFont(new, new->angband.font, FALSE);
577
578 /* The font didn't exist */
579 if (new->angband.fnt == NULL)
580 {
581 new->angband.fnt = current->angband.fnt;
582 new->angband.font = current->angband.font;
583 XtWarning("Couldn't find the request font!");
584 }
585 else
586 {
587 font_changed = TRUE;
588 /* Free the old font */
589 XFreeFont(XtDisplay((Widget)new), current->angband.fnt);
590 /* Update font information */
591 new->angband.fontheight = new->angband.fnt->ascent +
592 new->angband.fnt->descent;
593 new->angband.fontwidth = new->angband.fnt->max_bounds.width;
594 new->angband.fontascent = new->angband.fnt->ascent;
595 }
596 }
597
598 /* Check all colors, if one or more has changed the redo all GC's */
599 for (n = 0; n < NUM_COLORS; n++)
600 if (current->angband.color[n] != new->angband.color[n])
601 color_changed = TRUE;
602
603 /* Change all GC's if color or font has changed */
604 if (color_changed || font_changed)
605 {
606 gcv.font = new->angband.fnt->fid;
607 gcv.graphics_exposures = FALSE;
608 gcv.background = new->angband.color[0];
609
610 /* Do all GC's */
611 for (n = 0; n < NUM_COLORS; n++)
612 {
613 if (depth == 1 && n >= 1)
614 gcv.foreground = new->angband.color[1];
615 else
616 gcv.foreground = new->angband.color[n];
617 /* Release the old GC */
618 XtReleaseGC((Widget)current, current->angband.gc[n]);
619 /* Get the new GC */
620 new->angband.gc[n] = XtGetGC((Widget)new, GCFont | GCForeground |
621 GCBackground | GCGraphicsExposures,
622 &gcv);
623 }
624
625 /* Replace the old XOR/highlighting GC */
626 gcv.foreground = BlackPixelOfScreen(XtScreen((Widget)new)) ^
627 WhitePixelOfScreen(XtScreen((Widget)new));
628 gcv.function = GXxor;
629 XtReleaseGC((Widget)current, current->angband.gc[NUM_COLORS]);
630 new->angband.gc[NUM_COLORS] = XtGetGC((Widget)new, GCFunction |
631 GCGraphicsExposures |
632 GCForeground, &gcv);
633 /* Fix the background color */
634 new->core.background_pixel = new->angband.color[0];
635 }
636
637 /* Check if internal border width has changed, used later */
638 if (current->angband.internal_border != new->angband.internal_border)
639 border_changed = TRUE;
640
641
642 /* If the font or the internal border has changed, all geometry
643 has to be recalculated */
644 if (font_changed || border_changed)
645 {
646 /* Change window size */
647 height = (current->core.height - 2 * current->angband.internal_border) /
648 current->angband.fontheight * new->angband.fontheight +
649 2 * current->angband.internal_border;
650 width = (current->core.width - 2 * current->angband.internal_border) /
651 current->angband.fontwidth * new->angband.fontwidth +
652 2 * new->angband.internal_border;
653
654 /* Get the new width */
655 if (XtMakeResizeRequest((Widget)new, width, height, NULL, NULL) ==
656 XtGeometryNo)
657 {
658 /* Not allowed */
659 XtWarning("Size change denied!");
660 }
661 else
662 {
663 /* Recalculate size hints */
664 calculateSizeHints(new);
665 }
666 }
667
668 /* Tell it to redraw the widget if anything has changed */
669 return (font_changed || color_changed || border_changed);
670 }
671
672 /*
673 * Calculate size hints
674 */
calculateSizeHints(AngbandWidget new)675 static void calculateSizeHints(AngbandWidget new)
676 {
677 TopLevelShellWidget parent =
678 (TopLevelShellWidget)XtParent((Widget) new);
679
680 /* Calculate minimum size */
681 parent->wm.size_hints.min_height =
682 new->angband.min_rows * new->angband.fontheight +
683 2 * new->angband.internal_border;
684 parent->wm.size_hints.min_width =
685 new->angband.min_columns * new->angband.fontwidth +
686 2 * new->angband.internal_border;
687 parent->wm.size_hints.flags |= PMinSize;
688
689 /* Calculate maximum size */
690 parent->wm.size_hints.max_height =
691 new->angband.max_rows * new->angband.fontheight +
692 2 * new->angband.internal_border;
693 parent->wm.size_hints.max_width =
694 new->angband.max_columns * new->angband.fontwidth +
695 2 * new->angband.internal_border;
696 parent->wm.size_hints.flags |= PMaxSize;
697
698 /* Calculate increment size */
699 parent->wm.size_hints.height_inc = new->angband.fontheight;
700 parent->wm.size_hints.width_inc = new->angband.fontwidth;
701 parent->wm.size_hints.flags |= PResizeInc;
702
703 /* Calculate base size */
704 parent->wm.base_height = 2 * new->angband.internal_border;
705 parent->wm.base_width = 2 * new->angband.internal_border;
706 parent->wm.size_hints.flags |= PBaseSize;
707 }
708
709 /*
710 * Load a font
711 */
getFont(AngbandWidget widget,String font,Boolean fallback)712 static XFontStruct *getFont(AngbandWidget widget,
713 String font, Boolean fallback)
714 {
715 Display *dpy = XtDisplay((Widget) widget);
716 char buf[256];
717 XFontStruct *fnt = NULL;
718
719 if (!(fnt = XLoadQueryFont(dpy, font)) && fallback)
720 {
721 sprintf(buf, "Can't find the font \"%s\", trying fixed\n", font);
722 XtWarning(buf);
723 if (!(fnt = XLoadQueryFont(dpy, "fixed")))
724 XtError("Can't fint the font \"fixed\"!, bailing out\n");
725 }
726
727 return fnt;
728 }
729
730
731
732 /*** The non-widget code ****/
733
734 #ifndef IsModifierKey
735
736 /*
737 * Keysym macros, used on Keysyms to test for classes of symbols
738 * These were stolen from one of the X11 header files
739 */
740
741 #define IsKeypadKey(keysym) \
742 (((unsigned)(keysym) >= XK_KP_Space) && ((unsigned)(keysym) <= XK_KP_Equal))
743
744 #define IsCursorKey(keysym) \
745 (((unsigned)(keysym) >= XK_Home) && ((unsigned)(keysym) < XK_Select))
746
747 #define IsPFKey(keysym) \
748 (((unsigned)(keysym) >= XK_KP_F1) && ((unsigned)(keysym) <= XK_KP_F4))
749
750 #define IsFunctionKey(keysym) \
751 (((unsigned)(keysym) >= XK_F1) && ((unsigned)(keysym) <= XK_F35))
752
753 #define IsMiscFunctionKey(keysym) \
754 (((unsigned)(keysym) >= XK_Select) && ((unsigned)(keysym) < XK_KP_Space))
755
756 #define IsModifierKey(keysym) \
757 (((unsigned)(keysym) >= XK_Shift_L) && ((unsigned)(keysym) <= XK_Hyper_R))
758
759 #endif
760
761
762 /*
763 * Checks if the keysym is a special key or a normal key
764 * Assume that XK_MISCELLANY keysyms are special
765 */
766 #define IsSpecialKey(keysym) \
767 ((unsigned)(keysym) >= 0xFF00)
768
769
770 /*
771 * Forward declare
772 */
773 typedef struct term_data term_data;
774
775 /*
776 * A structure for each "term"
777 */
778 struct term_data
779 {
780 term t;
781
782 AngbandWidget widget;
783 };
784
785
786
787 /*
788 * The main screen
789 */
790
791 static term_data screen;
792
793 static Arg angbandArgs[] =
794 {
795 { XtNstartRows, 24},
796 { XtNstartColumns, 80},
797 { XtNminRows, 24},
798 { XtNminColumns, 80},
799 { XtNmaxRows, 24},
800 { XtNmaxColumns, 80}
801 };
802
803
804 #ifdef GRAPHIC_MIRROR
805
806 /*
807 * The mirror window
808 */
809
810 static term_data mirror;
811
812 Arg mirrorArgs[] =
813 {
814 { XtNstartRows, 24},
815 { XtNstartColumns, 80},
816 { XtNminRows, 1},
817 { XtNminColumns, 1},
818 { XtNmaxRows, 24},
819 { XtNmaxColumns, 80}
820 };
821
822 #endif /* GRAPHIC_MIRROR */
823
824 #ifdef GRAPHIC_RECALL
825
826 /*
827 * The "recall" window
828 */
829
830 static term_data recall;
831
832 Arg recallArgs[] =
833 {
834 { XtNstartRows, 8},
835 { XtNstartColumns, 80},
836 { XtNminRows, 1},
837 { XtNminColumns, 1},
838 { XtNmaxRows, 24},
839 { XtNmaxColumns, 80}
840 };
841
842 #endif /* GRAPHIC_RECALL */
843
844 #ifdef GRAPHIC_CHOICE
845
846 /*
847 * The "choice" window
848 */
849
850 static term_data choice;
851
852 Arg choiceArgs[] =
853 {
854 { XtNstartRows, 24},
855 { XtNstartColumns, 80},
856 { XtNminRows, 1},
857 { XtNminColumns, 1},
858 { XtNmaxRows, 24},
859 { XtNmaxColumns, 80}
860 };
861
862 #endif /* GRAPHIC_CHOICE */
863
864
865
866 /*
867 * The application context
868 */
869 XtAppContext appcon;
870
871 /*
872 * User changable information about widgets
873 */
874 static String fallback[] =
875 {
876 "Angband.angband.iconName: Angband",
877 "Angband.angband.title: Angband",
878 "Angband.mirror.iconName: Mirror",
879 "Angband.mirror.title: Mirror",
880 "Angband.recall.iconName: Recall",
881 "Angband.recall.title: Recall",
882 "Angband.choice.iconName: Choice",
883 "Angband.choice.title: Choice",
884 NULL
885 };
886
887
888
889 /*
890 * Do a redraw
891 */
react_redraw(Widget widget,XtPointer client_data,XtPointer call_data)892 static void react_redraw(Widget widget,
893 XtPointer client_data, XtPointer call_data)
894 {
895 term_data *old_td = (term_data*)(Term->data);
896 term_data *td = (term_data*)client_data;
897
898 /* Activate the proper Term */
899 Term_activate(&td->t);
900
901 /* Request a redraw */
902 Term_redraw();
903
904 /* Activate the old Term */
905 Term_activate(&old_td->t);
906 }
907
908 /*
909 * Process a keypress event
910 */
react_keypress(XKeyEvent * ev)911 static void react_keypress(XKeyEvent *ev)
912 {
913 int i, n, mc, ms, mo, mx;
914
915 KeySym ks;
916
917 char buf[128];
918 char msg[128];
919
920
921 /* Check for "normal" keypresses */
922 n = XLookupString(ev, buf, 125, &ks, NULL);
923
924 /* Terminate */
925 buf[n] = '\0';
926
927 /* Extract four "modifier flags" */
928 mc = (ev->state & ControlMask) ? TRUE : FALSE;
929 ms = (ev->state & ShiftMask) ? TRUE : FALSE;
930 mo = (ev->state & Mod1Mask) ? TRUE : FALSE;
931
932 /* This is the NumLock state and usually it only causes problems - mikaelh */
933 // mx = (ev->state & Mod2Mask) ? TRUE : FALSE;
934 mx = FALSE;
935
936 /* Hack -- Ignore "modifier keys" */
937 if (IsModifierKey(ks)) return;
938
939 /* Normal keys with no modifiers */
940 if (n && !mo && !mx && !IsSpecialKey(ks))
941 {
942 /* Enqueue the normal key(s) */
943 for (i = 0; buf[i]; i++) Term_keypress(buf[i]);
944
945 /* All done */
946 return;
947 }
948
949 /* Handle a few standard keys */
950 switch (ks)
951 {
952 case XK_Escape:
953 Term_keypress(ESCAPE); return;
954
955 case XK_Return:
956 Term_keypress('\r'); return;
957
958 case XK_Tab:
959 Term_keypress('\t'); return;
960
961 case XK_Delete:
962 case XK_BackSpace:
963 Term_keypress('\010'); return;
964 }
965
966 /* Hack -- Use the KeySym */
967 if (ks)
968 {
969 sprintf(msg, "%c%s%s%s%s_%lX%c", 31,
970 mc ? "N" : "", ms ? "S" : "",
971 mo ? "O" : "", mx ? "M" : "",
972 (unsigned long)(ks), 13);
973 }
974
975 /* Hack -- Use the Keycode */
976 else
977 {
978 sprintf(msg, "%c%s%s%s%sK_%X%c", 31,
979 mc ? "N" : "", ms ? "S" : "",
980 mo ? "O" : "", mx ? "M" : "",
981 ev->keycode, 13);
982 }
983
984 /* Enqueue the "fake" string */
985 for (i = 0; msg[i]; i++)
986 Term_keypress(msg[i]);
987
988 /* Hack -- dump an "extra" string */
989 if (n)
990 {
991 /* Start the "extra" string */
992 Term_keypress(28);
993
994 /* Enqueue the "real" string */
995 for (i = 0; buf[i]; i++)
996 Term_keypress(buf[i]);
997
998 /* End the "extra" string */
999 Term_keypress(28);
1000 }
1001 }
1002
1003
handle_event(Widget widget,XtPointer client_data,XEvent * event,Boolean * continue_to_dispatch)1004 static void handle_event (Widget widget, XtPointer client_data, XEvent *event,
1005 Boolean *continue_to_dispatch)
1006 {
1007 term_data *old_td = (term_data*)(Term->data);
1008 term_data *td = (term_data *)client_data;
1009
1010 /* Continue to process the event by default */
1011 *continue_to_dispatch = TRUE;
1012
1013 /* Activate the Term */
1014 Term_activate(&td->t);
1015
1016 switch (event->type)
1017 {
1018 case KeyPress:
1019 react_keypress(&(event->xkey));
1020 *continue_to_dispatch = FALSE; /* We took care of the event */
1021 break;
1022
1023 default:
1024 break; /* Huh? Shouldn't happen! */
1025 }
1026
1027 /* Activate the old term */
1028 Term_activate(&old_td->t);
1029
1030 return;
1031 }
1032
1033
1034 /*
1035 * Process an event (or just check for one)
1036 */
CheckEvent(bool wait)1037 errr CheckEvent(bool wait)
1038 {
1039 XEvent event;
1040
1041 /* No events ready, and told to just check */
1042 if (!wait && !XtAppPending(appcon)) return 1;
1043
1044 /* Process */
1045 while (1)
1046 {
1047 XtAppNextEvent(appcon, &event);
1048 XtDispatchEvent(&event);
1049 if (!XtAppPending(appcon)) break;
1050 }
1051
1052 return (0);
1053 }
1054
1055
1056 /*
1057 * Handle a "special request"
1058 */
Term_xtra_xaw(int n,int v)1059 static errr Term_xtra_xaw(int n, int v)
1060 {
1061 /* Handle a subset of the legal requests */
1062 switch (n)
1063 {
1064 /* Make a noise */
1065 case TERM_XTRA_NOISE:
1066 XBell(XtDisplay((Widget)screen.widget), 100);
1067 return (0);
1068
1069 /* Flush the output */
1070 case TERM_XTRA_FRESH:
1071 XFlush(XtDisplay((Widget)screen.widget));
1072 /* Nonblock event-check so the flushed events can be showed */
1073 CheckEvent(FALSE);
1074 return (0);
1075
1076 /* Process random events */
1077 case TERM_XTRA_BORED:
1078 return (CheckEvent(0));
1079
1080 /* Process events */
1081 case TERM_XTRA_EVENT:
1082 return (CheckEvent(v));
1083
1084 /* Flush events */
1085 case TERM_XTRA_FLUSH:
1086 while (!CheckEvent(FALSE));
1087 return (0);
1088
1089 /* Delay */
1090 case TERM_XTRA_DELAY:
1091 usleep(1000 * v);
1092 return (0);
1093
1094 /* Clear the window */
1095 case TERM_XTRA_CLEAR:
1096
1097 /* Screen */
1098 if (Term == &screen.t)
1099 {
1100 XClearWindow(XtDisplay((Widget)screen.widget),
1101 XtWindow((Widget)screen.widget));
1102 }
1103
1104 #ifdef GRAPHIC_MIRROR
1105 /* Mirror */
1106 if (Term == &mirror.t)
1107 {
1108 XClearWindow(XtDisplay((Widget)mirror.widget),
1109 XtWindow((Widget)mirror.widget));
1110 }
1111 #endif /* GRAPHIC_MIRROR */
1112
1113 #ifdef GRAPHIC_RECALL
1114 /* Recall */
1115 if (Term == &recall.t)
1116 {
1117 XClearWindow(XtDisplay((Widget)recall.widget),
1118 XtWindow((Widget)recall.widget));
1119 }
1120 #endif /* GRAPHIC_RECALL */
1121
1122 #ifdef GRAPHIC_CHOICE
1123 /* Choice */
1124 if (Term == &choice.t)
1125 {
1126 XClearWindow(XtDisplay((Widget)choice.widget),
1127 XtWindow((Widget)choice.widget));
1128 }
1129 #endif /* GRAPHIC_CHOICE */
1130
1131 return (0);
1132 }
1133
1134 /* Unknown */
1135 return (1);
1136 }
1137
1138
1139
1140 /*
1141 * Erase a number of characters
1142 */
Term_wipe_xaw(int x,int y,int n)1143 static errr Term_wipe_xaw(int x, int y, int n)
1144 {
1145 term_data *td = (term_data*)(Term->data);
1146
1147 /* Erase using color 0 */
1148 AngbandClearArea(td->widget, x, y, n, 1, 0);
1149
1150 /* Success */
1151 return (0);
1152 }
1153
1154
1155
1156 /*
1157 * Draw the cursor (XXX by hiliting)
1158 */
Term_curs_xaw(int x,int y)1159 static errr Term_curs_xaw(int x, int y)
1160 {
1161 term_data *td = (term_data*)(Term->data);
1162
1163 /* Hilite the cursor character */
1164 AngbandClearArea(td->widget, x, y, 1, 1, COLOR_XOR);
1165
1166 /* Success */
1167 return (0);
1168 }
1169
1170
1171 /*
1172 * Draw a number of characters
1173 */
Term_text_xaw(int x,int y,int n,byte a,cptr s)1174 static errr Term_text_xaw(int x, int y, int n, byte a, cptr s)
1175 {
1176 term_data *td = (term_data*)(Term->data);
1177
1178 /* Draw the text */
1179 AngbandOutputText(td->widget, x, y, (String)s, n, (a & 0x0F));
1180
1181 /* Success */
1182 return (0);
1183 }
1184
1185
1186 /*
1187 * Raise a term
1188 */
term_raise(term_data win)1189 static void term_raise(term_data win)
1190 {
1191 Widget widget = (Widget)win.widget;
1192
1193 XRaiseWindow(XtDisplay(XtParent(widget)), XtWindow(XtParent(widget)));
1194 }
1195
1196
1197 /*
1198 * Initialize a term_data
1199 */
term_data_init(term_data * td,Widget topLevel,int key_buf,String name,ArgList widget_arg,Cardinal widget_arg_no)1200 static errr term_data_init(term_data *td, Widget topLevel,
1201 int key_buf, String name,
1202 ArgList widget_arg, Cardinal widget_arg_no)
1203 {
1204 Widget parent;
1205 term *t = &td->t;
1206
1207 /* Create the shell widget */
1208 parent = XtCreatePopupShell(name, topLevelShellWidgetClass, topLevel,
1209 NULL, 0);
1210
1211 /* Create the interior widget */
1212 td->widget = (AngbandWidget)
1213 XtCreateManagedWidget (name, angbandWidgetClass,
1214 parent, widget_arg, widget_arg_no);
1215
1216 /* Initialize the term (full size) */
1217 term_init(t, 80, 24, key_buf);
1218
1219 /* Use a "soft" cursor */
1220 t->soft_cursor = TRUE;
1221
1222 /* Erase with "white space" */
1223 t->attr_blank = TERM_WHITE;
1224 t->char_blank = ' ';
1225
1226 /* Hooks */
1227 t->xtra_hook = Term_xtra_xaw;
1228 t->curs_hook = Term_curs_xaw;
1229 t->wipe_hook = Term_wipe_xaw;
1230 t->text_hook = Term_text_xaw;
1231
1232 /* Save the data */
1233 t->data = td;
1234
1235 /* Register the keypress event handler */
1236 XtAddEventHandler((Widget)td->widget, KeyPressMask,
1237 False, (XtEventHandler) handle_event, td);
1238
1239 /* Redraw callback */
1240 XtAddCallback((Widget)td->widget, XtNredrawCallback,
1241 react_redraw, td);
1242
1243 /* Realize the widget */
1244 XtRealizeWidget(parent);
1245
1246 /* Make it visible */
1247 XtPopup(parent, XtGrabNone);
1248
1249 /* Activate (important) */
1250 Term_activate(t);
1251
1252 return 0;
1253 }
1254
1255
1256 /*
1257 * Initialization function for an X Athena Widget module to Angband
1258 *
1259 * Mega-Hack -- we are not given the actual "argc" and "argv" from
1260 * the main program, so we fake one. Thus, we are unable to parse
1261 * any "display" requests for external devices. This is okay, since
1262 * we need to verify the display anyway, to work with "main.c".
1263 */
init_xaw(void)1264 errr init_xaw(void)
1265 {
1266 int argc;
1267 char *argv[2];
1268 Widget topLevel;
1269 Display *dpy;
1270
1271
1272 /* One fake argument */
1273 argc = 1;
1274
1275 /* Save the program name */
1276 argv[0] = (char*)argv0;
1277
1278 /* Terminate */
1279 argv[1] = NULL;
1280
1281
1282 /* Attempt to open the local display */
1283 dpy = XOpenDisplay("");
1284
1285 /* Failure -- assume no X11 available */
1286 if (!dpy) return (-1);
1287
1288 /* Close the local display */
1289 XCloseDisplay(dpy);
1290
1291
1292 #ifdef USE_XAW_LANG
1293 /* Support locale processing */
1294 XtSetLanguageProc(NULL, NULL, NULL);
1295 #endif
1296
1297 /* Initialize the toolkit */
1298 topLevel = XtAppInitialize (&appcon, "Angband", NULL, 0, &argc, argv,
1299 fallback, NULL, 0);
1300
1301 /* Get the socket for select() - mikaelh */
1302 x11_socket = ConnectionNumber(XtDisplay(topLevel));
1303
1304
1305 /* Initialize the main window */
1306 term_data_init (&screen, topLevel, 1024, "angband",
1307 angbandArgs, XtNumber(angbandArgs));
1308 term_screen = Term;
1309
1310 #ifdef GRAPHIC_MIRROR
1311 /* Initialize the mirror window */
1312 term_data_init (&mirror, topLevel, 16, "mirror",
1313 mirrorArgs, XtNumber(mirrorArgs));
1314 term_mirror = Term;
1315 #endif /* GRAPHIC_MIRROR */
1316
1317 #ifdef GRAPHIC_RECALL
1318 /* Initialize the recall window */
1319 term_data_init (&recall, topLevel, 16, "recall",
1320 recallArgs, XtNumber(recallArgs));
1321 term_recall = Term;
1322 #endif /* GRAPHIC_RECALL */
1323
1324 #ifdef GRAPHIC_CHOICE
1325 /* Initialize the choice window */
1326 term_data_init (&choice, topLevel, 16, "choice",
1327 choiceArgs, XtNumber(choiceArgs));
1328 term_choice = Term;
1329 #endif /* GRAPHIC_CHOICE */
1330
1331 /* Activate the "Angband" window screen */
1332 Term_activate(&screen.t);
1333
1334 /* Raise the "Angband" window */
1335 term_raise(screen);
1336
1337 /* Success */
1338 return (0);
1339 }
1340
1341 #endif
1342
1343