1 /* SCCS Id: @(#)winX.c 3.4 1999/12/21 */
2 /* Copyright (c) Dean Luick, 1992 */
3 /* NetHack may be freely redistributed. See license for details. */
6 * "Main" file for the X window-port. This contains most of the interface
7 * routines. Please see doc/window.doc for an description of the window
12 #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */
15 #ifdef MSDOS /* from compiler */
16 #define SHORT_FILENAMES
19 #include <X11/Intrinsic.h>
20 #include <X11/StringDefs.h>
21 #include <X11/Shell.h>
22 #include <X11/Xaw/AsciiText.h>
23 #include <X11/Xaw/Label.h>
24 #include <X11/Xaw/Form.h>
25 #include <X11/Xaw/Scrollbar.h>
26 #include <X11/Xaw/Paned.h>
27 #include <X11/Xaw/Cardinals.h>
28 #include <X11/Xatom.h>
31 /* for color support */
32 #ifdef SHORT_FILENAMES
33 #include <X11/IntrinsP.h>
35 #include <X11/IntrinsicP.h>
38 #ifdef PRESERVE_NO_SYSV
42 # undef PRESERVE_NO_SYSV
45 #ifdef SHORT_FILENAMES
46 #undef SHORT_FILENAMES /* hack.h will reset via global.h if necessary */
52 #ifdef SHORT_FILENAMES
55 #include "patchlevel.h"
58 /* Should be defined in <X11/Intrinsic.h> but you never know */
59 #ifndef XtSpecificationRelease
60 #define XtSpecificationRelease 0
66 #include "../win/X11/nh72icon"
67 #include "../win/X11/nh56icon"
68 #include "../win/X11/nh32icon"
70 static struct icon_info {
73 unsigned width, height;
75 { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height },
76 { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height },
77 { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height },
78 { (const char *)0, (unsigned char *)0, 0, 0 }
82 * Private global variables (shared among the window port files).
84 struct xwindow window_list[MAX_WINDOWS];
85 AppResources appResources;
86 void FDECL((*input_func), (Widget,XEvent *,String *,Cardinal *));
87 int click_x, click_y, click_button; /* Click position on a map window */
88 /* (filled by set_button_values()). */
89 int updated_inventory;
92 /* Interface definition, for windows.c */
93 struct window_procs X11_procs = {
95 WC_COLOR|WC_HILITE_PET,
102 X11_suspend_nhwindows,
103 X11_resume_nhwindows,
106 X11_display_nhwindow,
107 X11_destroy_nhwindow,
115 genl_message_menu, /* no need for X-specific handling */
116 X11_update_inventory,
137 #ifdef CHANGE_COLOR /* only a Mac option currently */
141 /* other defs that really should go away (they're tty specific) */
144 #ifdef GRAPHIC_TOMBSTONE
149 genl_preference_update,
155 static void FDECL(dismiss_file, (Widget, XEvent*, String*, Cardinal*));
156 static void FDECL(delete_file, (Widget, XEvent*, String*, Cardinal*));
157 static void FDECL(yn_key, (Widget, XEvent*, String*, Cardinal*));
158 static void FDECL(yn_delete, (Widget, XEvent*, String*, Cardinal*));
159 static void FDECL(askname_delete, (Widget, XEvent*, String*, Cardinal*));
160 static void FDECL(getline_delete, (Widget, XEvent*, String*, Cardinal*));
161 static void FDECL(X11_hangup, (Widget, XEvent*, String*, Cardinal*));
162 static int FDECL(input_event, (int));
163 static void FDECL(win_visible, (Widget,XtPointer,XEvent *,Boolean *));
164 static void NDECL(init_standard_windows);
170 static boolean x_inited = FALSE; /* TRUE if window system is set up. */
171 static winid message_win = WIN_ERR, /* These are the winids of the */
172 map_win = WIN_ERR, /* message, map, and status */
173 status_win = WIN_ERR; /* windows, when they are created */
174 /* in init_windows(). */
175 static Pixmap icon_pixmap = None; /* Pixmap for icon. */
178 * Find the window structure that corresponds to the given widget. Note
179 * that this is not the popup widget, nor the viewport, but the child.
188 /* Search to find the corresponding window. Look at the main widget, */
189 /* popup, the parent of the main widget, then parent of the widget. */
190 for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++)
191 if (wp->type != NHW_NONE &&
192 (wp->w == w || wp->popup == w || (wp->w && (XtParent(wp->w)) == w)
193 || (wp->popup == XtParent(w))))
196 if (windex == MAX_WINDOWS) panic("find_widget: can't match widget");
201 * Find a free window slot for use.
209 for (windex = 0, wp = &window_list[0]; windex < MAX_WINDOWS; windex++, wp++)
210 if (wp->type == NHW_NONE) break;
212 if (windex == MAX_WINDOWS)
213 panic("find_free_window: no free windows!");
214 return (winid) windex;
218 * Color conversion. The default X11 color converters don't try very
219 * hard to find matching colors in PseudoColor visuals. If they can't
220 * allocate the exact color, they puke and give you something stupid.
221 * This is an attempt to find some close readonly cell and use it.
223 XtConvertArgRec const nhcolorConvertArgs[] = {
224 {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.screen),
226 {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.colormap),
230 #define done(type, value) \
232 if (toVal->addr != 0) { \
233 if (toVal->size < sizeof(type)) { \
234 toVal->size = sizeof(type); \
237 *(type*)(toVal->addr) = (value); \
240 static type static_val; \
241 static_val = (value); \
242 toVal->addr = (genericptr_t)&static_val; \
244 toVal->size = sizeof(type); \
248 /* decl.h declares these, but it screws up structure references -dlc */
254 * Find a color that approximates the color named in "str". The "str" color
255 * may be a color name ("red") or number ("#7f0000"). If str == NULL, then
256 * "color" is assumed to contain the RGB color wanted.
257 * The approximate color found is returned in color as well.
258 * Return True if something close was found.
261 nhApproxColor(screen, colormap, str, color)
262 Screen *screen; /* screen to use */
263 Colormap colormap; /* the colormap to use */
264 char *str; /* color name */
265 XColor *color; /* the X color structure; changed only if successful */
268 long cdiff = 16777216; /* 2^24; hopefully our map is smaller */
270 static XColor *table = 0;
274 /* if the screen doesn't have a big colormap, don't waste our time */
275 /* or if it's huge, and _some_ match should have been possible */
276 if((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096)
279 if (str != (char *)0) {
280 if (!XParseColor(DisplayOfScreen(screen), colormap, str, &tmp))
284 tmp.flags = 7; /* force to use all 3 of RGB */
288 table = (XColor *) XtCalloc(ncells, sizeof(XColor));
289 for(i=0; i<ncells; i++)
291 XQueryColors(DisplayOfScreen(screen), colormap, table, ncells);
294 /* go thru cells and look for the one with smallest diff */
295 /* diff is calculated abs(reddiff)+abs(greendiff)+abs(bluediff) */
296 /* a more knowledgeable color person might improve this -dlc */
298 for(i=0; i<ncells; i++) {
299 if(table[i].flags == tmp.flags) {
300 j = (int)table[i].red - (int)tmp.red;
303 j = (int)table[i].green - (int)tmp.green;
306 j = (int)table[i].blue - (int)tmp.blue;
311 tmp.pixel = i; /* table[i].pixel == i */
316 if(cdiff == 16777216) return False; /* nothing found?! */
319 * Found something. Return it and mark this color as used to avoid
320 * reuse. Reuse causes major contrast problems :-)
322 *color = table[tmp.pixel];
323 table[tmp.pixel].flags = 0;
324 /* try to alloc the color, so no one else can change it */
325 if(!XAllocColor(DisplayOfScreen(screen), colormap, color)) {
333 nhCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret)
339 XtPointer *closure_ret;
341 String str = (String)fromVal->addr;
345 XtAppContext app = XtDisplayToApplicationContext(dpy);
349 Cardinal num_params=1;
351 if (*num_args != 2) {
352 XtAppWarningMsg(app, "wrongParameters", "cvtStringToPixel",
354 "String to pixel conversion needs screen and colormap arguments",
355 (String *)0, (Cardinal *)0);
359 screen = *((Screen **) args[0].addr);
360 colormap = *((Colormap *) args[1].addr);
362 /* If Xt colors, use the Xt routine and hope for the best */
363 #if (XtSpecificationRelease >= 5)
364 if ((strcmpi(str, XtDefaultBackground) == 0) ||
365 (strcmpi(str, XtDefaultForeground) == 0)) {
367 XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret);
370 if (strcmpi(str, XtDefaultBackground) == 0) {
371 *closure_ret = (char*)False;
372 done(Pixel, WhitePixelOfScreen(screen));
374 if (strcmpi(str, XtDefaultForeground) == 0) {
375 *closure_ret = (char*)False;
376 done(Pixel, BlackPixelOfScreen(screen));
380 status = XAllocNamedColor(DisplayOfScreen(screen), colormap,
381 (char*)str, &screenColor, &exactColor);
385 /* some versions of XAllocNamedColor don't allow #xxyyzz names */
387 XParseColor(DisplayOfScreen(screen), colormap, str, &exactColor) &&
388 XAllocColor(DisplayOfScreen(screen), colormap, &exactColor)) {
389 *closure_ret = (char*)True;
390 done(Pixel, exactColor.pixel);
394 /* Server returns a specific error code but Xlib discards it. Ugh */
395 if (XLookupColor(DisplayOfScreen(screen), colormap, (char*)str,
396 &exactColor, &screenColor)) {
397 /* try to find another color that will do */
398 if (nhApproxColor(screen, colormap, (char*) str, &screenColor)) {
399 *closure_ret = (char*)True;
400 done(Pixel, screenColor.pixel);
403 msg = "Cannot allocate colormap entry for \"%s\"";
406 /* some versions of XLookupColor also don't allow #xxyyzz names */
408 (nhApproxColor(screen, colormap, (char*) str, &screenColor))) {
409 *closure_ret = (char*)True;
410 done(Pixel, screenColor.pixel);
413 msg = "Color name \"%s\" is not defined";
416 XtAppWarningMsg(app, type, "cvtStringToPixel",
417 "XtToolkitError", msg, params, &num_params);
418 *closure_ret = False;
421 *closure_ret = (char*)True;
422 done(Pixel, screenColor.pixel);
428 nhFreePixel(app, toVal, closure, args, num_args)
438 if (*num_args != 2) {
439 XtAppWarningMsg(app, "wrongParameters",
440 "freePixel", "XtToolkitError",
441 "Freeing a pixel requires screen and colormap arguments",
442 (String *)0, (Cardinal *)0);
446 screen = *((Screen **) args[0].addr);
447 colormap = *((Colormap *) args[1].addr);
450 XFreeColors( DisplayOfScreen(screen), colormap,
451 (unsigned long*)toVal->addr, 1, (unsigned long)0
456 /* [ALI] Utility function to ask Xaw for font height, since the previous
457 * assumption of ascent + descent is not always valid.
462 #ifdef _XawTextSink_h
465 XawTextPosition pos = 0;
466 int resWidth, resHeight;
469 XtSetArg(args[0], XtNtextSink, &sink);
470 XtGetValues(w, args, 1);
472 XawTextSinkFindPosition(sink, pos, 0, 0, 0, &pos, &resWidth, &resHeight);
480 XtSetArg(args[0], XtNfont, &fs);
481 XtGetValues(w, args, 1);
483 /* Assume font height is ascent + descent. */
484 return = fs->ascent + fs->descent;
488 /* Global Functions ======================================================== */
497 X11_raw_print_bold(str)
504 X11_curs(window, x, y)
510 if (x < 0 || x >= COLNO) {
511 impossible("curs: bad x value [%d]", x);
514 if (y < 0 || y >= ROWNO) {
515 impossible("curs: bad y value [%d]", y);
519 window_list[window].cursx = x;
520 window_list[window].cursy = y;
524 X11_putstr(window, attr, str)
533 wp = &window_list[window];
537 (void) strncpy(toplines, str, TBUFSZ); /* for Norep(). */
538 toplines[TBUFSZ - 1] = 0;
539 append_message(wp, str);
542 adjust_status(wp, str);
545 impossible("putstr: called on map window \"%s\"", str);
548 if (wp->menu_information->is_menu) {
550 "putstr: called on a menu window, \"%s\" discarded",
555 * Change this menu window into a text window by creating a
556 * new text window, then copying it to this winid.
558 new_win = X11_create_nhwindow(NHW_TEXT);
559 X11_destroy_nhwindow(window);
560 *wp = window_list[new_win];
561 window_list[new_win].type = NHW_NONE; /* allow re-use */
562 /* fall though to add text */
564 add_to_text_window(wp, attr, str);
567 impossible("putstr: unknown window type [%d] \"%s\"",
572 /* We do event processing as a callback, so this is a null routine. */
573 void X11_get_nh_event() { return; }
578 return input_event(EXIT_ON_KEY_PRESS);
583 X11_nh_poskey(x, y, mod)
586 int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
588 if (val == 0) { /* user clicked on a map window */
598 X11_create_nhwindow(type)
605 panic("create_nhwindow: windows not initialized");
608 * We have already created the standard message, map, and status
609 * windows in the window init routine. The first window of that
610 * type to be created becomes the standard.
612 * A better way to do this would be to say that init_nhwindows()
613 * has already defined these three windows.
615 if (type == NHW_MAP && map_win != WIN_ERR) {
620 if (type == NHW_MESSAGE && message_win != WIN_ERR) {
621 window = message_win;
622 message_win = WIN_ERR;
625 if (type == NHW_STATUS && status_win != WIN_ERR) {
627 status_win = WIN_ERR;
631 window = find_free_window();
632 wp = &window_list[window];
634 /* The create routines will set type, popup, w, and Win_info. */
635 wp->prevx = wp->prevy = wp->cursx = wp->cursy =
636 wp->pixel_width = wp->pixel_height = 0;
637 wp->keep_window = FALSE;
641 create_map_window(wp, TRUE, (Widget) 0);
644 create_message_window(wp, TRUE, (Widget) 0);
647 create_status_window(wp, TRUE, (Widget) 0);
650 create_menu_window(wp);
653 create_text_window(wp);
656 panic("create_nhwindow: unknown type [%d]", type);
663 X11_clear_nhwindow(window)
669 wp = &window_list[window];
672 case NHW_MAP: clear_map_window(wp); break;
673 case NHW_TEXT: clear_text_window(wp); break;
677 /* do nothing for these window types */
680 panic("clear_nhwindow: unknown window type [%d]", wp->type);
686 X11_display_nhwindow(window, blocking)
693 wp = &window_list[window];
698 nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
699 display_map_window(wp); /* flush map */
701 * We need to flush the message window here due to the way the tty
702 * port is set up. To flush a window, you need to call this
703 * routine. However, the tty port _pauses_ with a --more-- if we
704 * do a display_nhwindow(WIN_MESSAGE, FALSE). Thus, we can't call
705 * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we
706 * get a --more-- after every line.
708 * Perhaps the window document should mention that when the map
709 * is flushed, everything on the three main windows should be
710 * flushed. Note: we don't need to flush the status window
711 * because we don't buffer changes.
713 if (WIN_MESSAGE != WIN_ERR)
714 display_message_window(&window_list[WIN_MESSAGE]);
716 (void) x_event(EXIT_ON_KEY_OR_BUTTON_PRESS);
720 nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
721 display_message_window(wp); /* flush messages */
725 nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w);
726 break; /* no flushing necessary */
732 n = X11_select_menu(window, PICK_NONE, &selected);
734 impossible("perminvent: %d selected??", n);
735 free((genericptr_t)selected);
740 display_text_window(wp, blocking); /* pop up text window */
743 panic("display_nhwindow: unknown window type [%d]", wp->type);
749 X11_destroy_nhwindow(window)
755 wp = &window_list[window];
757 * "Zap" known windows, but don't destroy them. We need to keep the
758 * toplevel widget popped up so that later windows (e.g. tombstone)
759 * are visible on DECWindow systems. This is due to the virtual
760 * roots that the DECWindow wm creates.
762 if (window == WIN_MESSAGE) {
763 wp->keep_window = TRUE;
764 WIN_MESSAGE = WIN_ERR;
765 iflags.window_inited = 0;
766 } else if (window == WIN_MAP) {
767 wp->keep_window = TRUE;
769 } else if (window == WIN_STATUS) {
770 wp->keep_window = TRUE;
771 WIN_STATUS = WIN_ERR;
772 } else if (window == WIN_INVEN) {
773 /* don't need to keep this one */
779 destroy_map_window(wp);
782 destroy_menu_window(wp);
785 destroy_text_window(wp);
788 destroy_status_window(wp);
791 destroy_message_window(wp);
794 panic("destroy_nhwindow: unknown window type [%d]", wp->type);
800 X11_update_inventory()
802 if (x_inited && window_list[WIN_INVEN].menu_information->is_up) {
803 updated_inventory = 1; /* hack to avoid mapping&raising window */
804 (void) display_inventory((char *)0, FALSE);
805 updated_inventory = 0;
809 /* The current implementation has all of the saved lines on the screen. */
810 int X11_doprev_message() { return 0; }
815 /* We can't use XBell until toplevel has been initialized. */
817 XBell(XtDisplay(toplevel), 0);
818 /* else print ^G ?? */
821 void X11_mark_synch()
825 * The window document is unclear about the status of text
826 * that has been pline()d but not displayed w/display_nhwindow().
827 * Both the main and tty code assume that a pline() followed
828 * by mark_synch() results in the text being seen, even if
829 * display_nhwindow() wasn't called. Duplicate this behavior.
831 if (WIN_MESSAGE != WIN_ERR)
832 display_message_window(&window_list[WIN_MESSAGE]);
833 XSync(XtDisplay(toplevel), False);
837 void X11_wait_synch() { if (x_inited) XFlush(XtDisplay(toplevel)); }
840 /* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */
841 void X11_resume_nhwindows() { return; }
844 void X11_suspend_nhwindows(str) const char *str; { return; }
846 /* Under X, we don't need to initialize the number pad. */
848 void X11_number_pad(state) int state; { return; } /* called from options.c */
851 void X11_start_screen() { return; } /* called from setftty() in unixtty.c */
852 void X11_end_screen() { return; } /* called from settty() in unixtty.c */
854 #ifdef GRAPHIC_TOMBSTONE
855 void X11_outrip(window, how)
862 wp = &window_list[window];
864 if (wp->type == NHW_TEXT) {
865 wp->text_information->is_rip = TRUE;
867 panic("ripout on non-text window (window type [%d])", wp->type);
870 calculate_rip_text(how);
874 /* init and exit nhwindows ------------------------------------------------- */
876 XtAppContext app_context; /* context of application */
877 Widget toplevel = (Widget) 0; /* toplevel widget */
878 Atom wm_delete_window; /* pop down windows */
880 static XtActionsRec actions[] = {
881 {"dismiss_file", dismiss_file}, /* action for file viewing widget */
882 {"delete_file", delete_file}, /* action for file delete-window */
883 {"dismiss_text", dismiss_text}, /* button action for text widget */
884 {"delete_text", delete_text}, /* delete action for text widget */
885 {"key_dismiss_text",key_dismiss_text},/* key action for text widget */
886 #ifdef GRAPHIC_TOMBSTONE
887 {"rip_dismiss_text",rip_dismiss_text},/* action for rip in text widget */
889 {"menu_key", menu_key}, /* action for menu accelerators */
890 {"yn_key", yn_key}, /* action for yn accelerators */
891 {"yn_delete", yn_delete}, /* action for yn delete-window */
892 {"askname_delete", askname_delete},/* action for askname delete-window */
893 {"getline_delete", getline_delete},/* action for getline delete-window */
894 {"menu_delete", menu_delete}, /* action for menu delete-window */
895 {"ec_key", ec_key}, /* action for extended commands */
896 {"ec_delete", ec_delete}, /* action for ext-com menu delete */
897 {"ps_key", ps_key}, /* action for player selection */
898 {"race_key", race_key}, /* action for race selection */
899 {"gend_key", gend_key}, /* action for gender selection */
900 {"algn_key", algn_key}, /* action for alignment selection */
901 {"X11_hangup", X11_hangup}, /* action for delete of top-level */
902 {"input", map_input}, /* action for key input */
903 {"scroll", nh_keyscroll}, /* action for scrolling by keys */
906 static XtResource resources[] = {
907 { "slow", "Slow", XtRBoolean, sizeof(Boolean),
908 XtOffset(AppResources *,slow), XtRString, "True" },
909 { "autofocus", "AutoFocus", XtRBoolean, sizeof(Boolean),
910 XtOffset(AppResources *,autofocus), XtRString, "False" },
911 { "message_line", "Message_line", XtRBoolean, sizeof(Boolean),
912 XtOffset(AppResources *,message_line), XtRString, "False" },
913 { "double_tile_size", "Double_tile_size", XtRBoolean, sizeof(Boolean),
914 XtOffset(AppResources *,double_tile_size), XtRString, "False" },
915 { "tile_file", "Tile_file", XtRString, sizeof(String),
916 XtOffset(AppResources *,tile_file), XtRString, "" },
917 { "icon", "Icon", XtRString, sizeof(String),
918 XtOffset(AppResources *,icon), XtRString, "nh72" },
919 { "message_lines", "Message_lines", XtRInt, sizeof(int),
920 XtOffset(AppResources *,message_lines), XtRString, "12" },
921 { "pet_mark_bitmap", "Pet_mark_bitmap", XtRString, sizeof(String),
922 XtOffset(AppResources *,pet_mark_bitmap), XtRString, "pet_mark.xbm" },
923 { "pet_mark_color", "Pet_mark_color", XtRPixel, sizeof(XtRPixel),
924 XtOffset(AppResources *,pet_mark_color), XtRString, "Red" },
925 #ifdef GRAPHIC_TOMBSTONE
926 { "tombstone", "Tombstone", XtRString, sizeof(String),
927 XtOffset(AppResources *,tombstone), XtRString, "rip.xpm" },
928 { "tombtext_x", "Tombtext_x", XtRInt, sizeof(int),
929 XtOffset(AppResources *,tombtext_x), XtRString, "155" },
930 { "tombtext_y", "Tombtext_y", XtRInt, sizeof(int),
931 XtOffset(AppResources *,tombtext_y), XtRString, "78" },
932 { "tombtext_dx", "Tombtext_dx", XtRInt, sizeof(int),
933 XtOffset(AppResources *,tombtext_dx), XtRString, "0" },
934 { "tombtext_dy", "Tombtext_dy", XtRInt, sizeof(int),
935 XtOffset(AppResources *,tombtext_dy), XtRString, "13" },
940 X11_init_nhwindows(argcp,argv)
944 static const char *banner_text[] = {
952 register const char **pp;
958 /* Init windows to nothing. */
959 for (i = 0; i < MAX_WINDOWS; i++)
960 window_list[i].type = NHW_NONE;
963 * setuid hack: make sure that if nethack is setuid, to use real uid
964 * when opening X11 connections, in case the user is using xauth, since
965 * the "games" or whatever user probably doesn't have permission to open
966 * a window on the user's display. This code is harmless if the binary
967 * is not installed setuid. See include/system.h on compilation failures.
970 (void) seteuid(getuid());
972 XSetIOErrorHandler((XIOErrorHandler) hangup);
975 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
976 toplevel = XtAppInitialize(
978 "NetHack", /* application class */
979 (XrmOptionDescList)0, 0, /* options list */
980 argcp, (String *)argv, /* command line args */
981 (String *)0, /* fallback resources */
982 (ArgList)args, num_args);
983 XtOverrideTranslations(toplevel,
984 XtParseTranslationTable("<Message>WM_PROTOCOLS: X11_hangup()"));
986 /* We don't need to realize the top level widget. */
989 /* add new color converter to deal with overused colormaps */
990 XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel,
991 (XtConvertArgList)nhcolorConvertArgs,
992 XtNumber(nhcolorConvertArgs),
993 XtCacheByDisplay, nhFreePixel);
994 #endif /* TEXTCOLOR */
996 /* Register the actions mentioned in "actions". */
997 XtAppAddActions(app_context, actions, XtNumber(actions));
999 /* Get application-wide resources */
1000 XtGetApplicationResources(toplevel, (XtPointer)&appResources,
1001 resources, XtNumber(resources),
1004 /* Initialize other things. */
1005 init_standard_windows();
1007 /* Give the window manager an icon to use; toplevel must be realized. */
1008 if (appResources.icon && *appResources.icon) {
1009 struct icon_info *ip;
1011 for (ip = icon_data; ip->name; ip++)
1012 if (!strcmp(appResources.icon, ip->name)) {
1013 icon_pixmap = XCreateBitmapFromData(XtDisplay(toplevel),
1015 (genericptr_t)ip->bits, ip->width, ip->height);
1016 if (icon_pixmap != None) {
1019 (void) memset((genericptr_t)&hints, 0, sizeof(XWMHints));
1020 hints.flags = IconPixmapHint;
1021 hints.icon_pixmap = icon_pixmap;
1022 XSetWMHints(XtDisplay(toplevel),
1023 XtWindow(toplevel), &hints);
1029 /* end of setuid hack: reset uid back to the "games" uid */
1030 (void) seteuid(savuid);
1032 x_inited = TRUE; /* X is now initialized */
1034 /* Display the startup banner in the message window. */
1035 for (pp = banner_text; *pp; pp++)
1036 X11_putstr(WIN_MESSAGE, 0, *pp);
1043 void X11_exit_nhwindows(dummy)
1046 extern Pixmap tile_pixmap; /* from winmap.c */
1048 /* explicitly free the icon and tile pixmaps */
1049 if (icon_pixmap != None) {
1050 XFreePixmap(XtDisplay(toplevel), icon_pixmap);
1053 if (tile_pixmap != None) {
1054 XFreePixmap(XtDisplay(toplevel), tile_pixmap);
1057 if (WIN_INVEN != WIN_ERR)
1058 X11_destroy_nhwindow(WIN_INVEN);
1059 if (WIN_STATUS != WIN_ERR)
1060 X11_destroy_nhwindow(WIN_STATUS);
1061 if (WIN_MAP != WIN_ERR)
1062 X11_destroy_nhwindow(WIN_MAP);
1063 if (WIN_MESSAGE != WIN_ERR)
1064 X11_destroy_nhwindow(WIN_MESSAGE);
1068 /* delay_output ------------------------------------------------------------ */
1071 * Timeout callback for delay_output(). Send a fake message to the map
1076 d_timeout(client_data, id)
1077 XtPointer client_data;
1081 XClientMessageEvent *mesg;
1083 /* Set up a fake message to the event handler. */
1084 mesg = (XClientMessageEvent *) &event;
1085 mesg->type = ClientMessage;
1086 mesg->message_type = XA_STRING;
1088 XSendEvent(XtDisplay(window_list[WIN_MAP].w),
1089 XtWindow(window_list[WIN_MAP].w),
1096 * Delay for 50ms. This is not implemented asynch. Maybe later.
1097 * Start the timeout, then wait in the event loop. The timeout
1098 * function will send an event to the map window which will be waiting
1104 if (!x_inited) return;
1106 (void) XtAppAddTimeOut(app_context, 30L, d_timeout, (XtPointer) 0);
1108 /* The timeout function will enable the event loop exit. */
1109 (void) x_event(EXIT_ON_SENT_EVENT);
1112 /* X11_hangup -------------------------------------------------------------- */
1115 X11_hangup(w, event, params, num_params)
1119 Cardinal *num_params;
1121 hangup(1); /* 1 is commonly SIGHUP, but ignored anyway */
1124 /* askname ----------------------------------------------------------------- */
1127 askname_delete(w, event, params, num_params)
1131 Cardinal *num_params;
1134 (void) strcpy(plname, "Mumbles"); /* give them a name... ;-) */
1135 exit_x_event = TRUE;
1138 /* Callback for askname dialog widget. */
1141 askname_done(w, client_data, call_data)
1143 XtPointer client_data;
1144 XtPointer call_data;
1148 Widget dialog = (Widget) client_data;
1150 s = (char *) GetDialogResponse(dialog);
1158 /* Truncate name if necessary */
1159 if (len >= sizeof(plname)-1)
1160 len = sizeof(plname)-1;
1162 (void) strncpy(plname, s, len);
1166 nh_XtPopdown(XtParent(dialog));
1167 exit_x_event = TRUE;
1173 Widget popup, dialog;
1176 XtSetArg(args[0], XtNallowShellResize, True);
1178 popup = XtCreatePopupShell("askname", transientShellWidgetClass,
1179 toplevel, args, ONE);
1180 XtOverrideTranslations(popup,
1181 XtParseTranslationTable("<Message>WM_PROTOCOLS: askname_delete()"));
1183 dialog = CreateDialog(popup, "dialog",
1184 askname_done, (XtCallbackProc) 0);
1186 SetDialogPrompt(dialog, "What is your name?"); /* set prompt */
1187 SetDialogResponse(dialog, ""); /* set default answer */
1189 XtRealizeWidget(popup);
1190 positionpopup(popup, TRUE); /* center,bottom */
1192 nh_XtPopup(popup, (int)XtGrabExclusive, dialog);
1194 /* The callback will enable the event loop exit. */
1195 (void) x_event(EXIT_ON_EXIT);
1199 /* getline ----------------------------------------------------------------- */
1200 /* This uses Tim Theisen's dialog widget set (from GhostView). */
1202 static Widget getline_popup, getline_dialog;
1204 #define CANCEL_STR "\033"
1205 static char *getline_input;
1208 /* Callback for getline dialog widget. */
1211 done_button(w, client_data, call_data)
1213 XtPointer client_data;
1214 XtPointer call_data;
1218 Widget dialog = (Widget) client_data;
1220 s = (char *) GetDialogResponse(dialog);
1223 /* Truncate input if necessary */
1224 if (len >= BUFSZ) len = BUFSZ - 1;
1226 (void) strncpy(getline_input, s, len);
1227 getline_input[len] = '\0';
1230 nh_XtPopdown(XtParent(dialog));
1231 exit_x_event = TRUE;
1236 getline_delete(w, event, params, num_params)
1240 Cardinal *num_params;
1242 Strcpy(getline_input, CANCEL_STR);
1244 exit_x_event = TRUE;
1247 /* Callback for getline dialog widget. */
1250 abort_button(w, client_data, call_data)
1252 XtPointer client_data;
1253 XtPointer call_data;
1255 Widget dialog = (Widget) client_data;
1257 Strcpy(getline_input, CANCEL_STR);
1258 nh_XtPopdown(XtParent(dialog));
1259 exit_x_event = TRUE;
1264 X11_getlin(question, input)
1265 const char *question;
1268 static boolean need_to_init = True;
1270 getline_input = input;
1276 need_to_init = False;
1278 XtSetArg(args[0], XtNallowShellResize, True);
1280 getline_popup = XtCreatePopupShell("getline",transientShellWidgetClass,
1281 toplevel, args, ONE);
1282 XtOverrideTranslations(getline_popup,
1283 XtParseTranslationTable("<Message>WM_PROTOCOLS: getline_delete()"));
1285 getline_dialog = CreateDialog(getline_popup, "dialog",
1286 done_button, abort_button);
1288 XtRealizeWidget(getline_popup);
1289 XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup),
1290 &wm_delete_window, 1);
1292 SetDialogPrompt(getline_dialog, (String)question); /* set prompt */
1293 SetDialogResponse(getline_dialog, ""); /* set default answer */
1294 positionpopup(getline_popup, TRUE); /* center,bottom */
1296 nh_XtPopup(getline_popup, (int)XtGrabExclusive, getline_dialog);
1298 /* The callback will enable the event loop exit. */
1299 (void) x_event(EXIT_ON_EXIT);
1303 /* Display file ------------------------------------------------------------ */
1304 static const char display_translations[] =
1306 <Key>q: dismiss_file()\n\
1307 <Key>Escape: dismiss_file()\n\
1308 <BtnDown>: dismiss_file()";
1311 /* WM_DELETE_WINDOW callback for file dismissal. */
1314 delete_file(w, event, params, num_params)
1318 Cardinal *num_params;
1324 /* Callback for file dismissal. */
1327 dismiss_file(w, event, params, num_params)
1331 Cardinal *num_params;
1333 Widget popup = XtParent(w);
1334 nh_XtPopdown(popup);
1335 XtDestroyWidget(popup);
1339 X11_display_file(str, complain)
1346 Widget popup, dispfile;
1347 Position top_margin, bottom_margin, left_margin, right_margin;
1349 int new_width, new_height;
1356 /* Use the port-independent file opener to see if the file exists. */
1357 fp = dlb_fopen(str, RDTMODE);
1360 if(complain) pline("Cannot open %s. Sorry.", str);
1362 return; /* it doesn't exist, ignore */
1366 * Count the number of lines and characters in the file.
1370 while (dlb_fgets(line, LLEN, fp)) {
1372 charcount += strlen(line);
1375 (void) dlb_fclose(fp);
1377 /* Ignore empty files */
1378 if (num_lines == 0) return;
1380 /* If over the max window size, truncate the window size to the max */
1381 if (num_lines >= DISPLAY_FILE_SIZE)
1382 num_lines = DISPLAY_FILE_SIZE;
1385 * Re-open the file and read the data into a buffer. Cannot use
1386 * the XawAsciiFile type of widget, because that is not DLB-aware.
1388 textlines = (char *) alloc((unsigned int) charcount);
1389 textlines[0] = '\0';
1391 fp = dlb_fopen(str, RDTMODE);
1393 while (dlb_fgets(line, LLEN, fp)) {
1394 (void) strcat(textlines, line);
1397 (void) dlb_fclose(fp);
1400 XtSetArg(args[num_args], XtNtitle, str); num_args++;
1402 popup = XtCreatePopupShell("display_file", topLevelShellWidgetClass,
1403 toplevel, args, num_args);
1404 XtOverrideTranslations(popup,
1405 XtParseTranslationTable("<Message>WM_PROTOCOLS: delete_file()"));
1408 XtSetArg(args[num_args], XtNscrollHorizontal,
1409 XawtextScrollWhenNeeded); num_args++;
1410 XtSetArg(args[num_args], XtNscrollVertical,
1411 XawtextScrollWhenNeeded); num_args++;
1412 XtSetArg(args[num_args], XtNtype, XawAsciiString); num_args++;
1413 XtSetArg(args[num_args], XtNstring, textlines); num_args++;
1414 XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++;
1415 XtSetArg(args[num_args], XtNtranslations,
1416 XtParseTranslationTable(display_translations)); num_args++;
1418 dispfile = XtCreateManagedWidget(
1420 asciiTextWidgetClass,
1421 popup, /* parent widget */
1422 args, /* set some values */
1423 num_args); /* number of values to set */
1425 /* Get font and border information. */
1427 XtSetArg(args[num_args], XtNfont, &fs); num_args++;
1428 XtSetArg(args[num_args], XtNtopMargin, &top_margin); num_args++;
1429 XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++;
1430 XtSetArg(args[num_args], XtNleftMargin, &left_margin); num_args++;
1431 XtSetArg(args[num_args], XtNrightMargin, &right_margin); num_args++;
1432 XtGetValues(dispfile, args, num_args);
1435 * The data files are currently set up assuming an 80 char wide window
1436 * and a fixed width font. Soo..
1438 new_height = num_lines * nhFontHeight(dispfile) +
1439 top_margin + bottom_margin;
1440 new_width = 80 * fs->max_bounds.width + left_margin + right_margin;
1442 /* Set the new width and height. */
1444 XtSetArg(args[num_args], XtNwidth, new_width); num_args++;
1445 XtSetArg(args[num_args], XtNheight, new_height); num_args++;
1446 XtSetValues(dispfile, args, num_args);
1448 nh_XtPopup(popup, (int)XtGrabNone, (Widget)0);
1453 /* yn_function ------------------------------------------------------------- */
1454 /* (not threaded) */
1456 static const char *yn_quitchars = " \n\r";
1457 static const char *yn_choices; /* string of acceptable input */
1459 static char yn_return; /* return value */
1460 static char yn_esc_map; /* ESC maps to this char. */
1461 static Widget yn_popup; /* popup for the yn fuction (created once) */
1462 static Widget yn_label; /* label for yn function (created once) */
1463 static boolean yn_getting_num; /* TRUE if accepting digits */
1464 static int yn_ndigits; /* digit count */
1465 static long yn_val; /* accumulated value */
1467 static const char yn_translations[] =
1472 * Convert the given key event into a character. If the key maps to
1473 * more than one character only the first is returned. If there is
1474 * no conversion (i.e. just the CTRL key hit) a NUL is returned.
1477 key_event_to_char(key)
1480 char keystring[MAX_KEY_STRING];
1482 boolean meta = !!(key->state & Mod1Mask);
1484 nbytes = XLookupString(key, keystring, MAX_KEY_STRING,
1485 (KeySym *)0, (XComposeStatus *)0);
1487 /* Modifier keys return a zero lengh string when pressed. */
1488 if (nbytes == 0) return '\0';
1490 return (char) (((int) keystring[0]) + (meta ? 0x80 : 0));
1494 * Called when we get a WM_DELETE_WINDOW event on a yn window.
1498 yn_delete(w, event, params, num_params)
1502 Cardinal *num_params;
1504 yn_getting_num = FALSE;
1505 /* Only use yn_esc_map if we have choices. Otherwise, return ESC. */
1506 yn_return = yn_choices ? yn_esc_map : '\033';
1507 exit_x_event = TRUE; /* exit our event handler */
1511 * Called when we get a key press event on a yn window.
1515 yn_key(w, event, params, num_params)
1519 Cardinal *num_params;
1523 if(appResources.slow && !input_func)
1524 map_input(w, event, params, num_params);
1526 ch = key_event_to_char((XKeyEvent *) event);
1528 if (ch == '\0') { /* don't accept nul char or modifier event */
1533 if (!yn_choices) { /* accept any input */
1536 ch = lowc(ch); /* move to lower case */
1539 yn_getting_num = FALSE;
1540 yn_return = yn_esc_map;
1541 } else if (index(yn_quitchars, ch)) {
1543 } else if (index(yn_choices, ch)) {
1545 if (yn_getting_num) { /* don't select again */
1549 yn_getting_num = TRUE;
1552 return; /* wait for more input */
1555 if (ch != 'y') yn_getting_num = FALSE;
1557 if (yn_getting_num) {
1560 yn_val = (yn_val * 10) + (long) (ch - '0');
1561 return; /* wait for more input */
1563 if (yn_ndigits && (ch == '\b' || ch == 127/*DEL*/)) {
1565 yn_val = yn_val/ 10;
1566 return; /* wait for more input */
1569 X11_nhbell(); /* no match */
1573 if (yn_getting_num) {
1575 if (yn_val < 0) yn_val = 0;
1576 yn_number = yn_val; /* assign global */
1579 exit_x_event = TRUE; /* exit our event handler */
1584 X11_yn_function(ques, choices, def)
1586 const char *choices;
1589 static Boolean need_to_init = True;
1594 yn_choices = choices; /* set up globals for callback to use */
1598 * This is sort of a kludge. There are quite a few places in the main
1599 * nethack code where a pline containing information is followed by a
1600 * call to yn_function(). There is no flush of the message window
1601 * (it is implicit in the tty window port), so the line never shows
1602 * up for us! Solution: do our own flush.
1604 if (WIN_MESSAGE != WIN_ERR)
1605 display_message_window(&window_list[WIN_MESSAGE]);
1608 char *cb, choicebuf[QBUFSZ];
1610 Strcpy(choicebuf, choices); /* anything beyond <esc> is hidden */
1611 if ((cb = index(choicebuf, '\033')) != 0) *cb = '\0';
1612 /* ques [choices] (def) */
1613 if ((int)(1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= QBUFSZ)
1614 panic("yn_function: question too long");
1615 Sprintf(buf, "%s [%s] ", ques, choicebuf);
1616 if (def) Sprintf(eos(buf), "(%c) ", def);
1618 /* escape maps to 'q' or 'n' or default, in that order */
1619 yn_esc_map = (index(choices, 'q') ? 'q' :
1620 (index(choices, 'n') ? 'n' :
1623 if ((int)(1 + strlen(ques)) >= QBUFSZ)
1624 panic("yn_function: question too long");
1628 if (!appResources.slow && need_to_init) {
1629 need_to_init = False;
1631 XtSetArg(args[0], XtNallowShellResize, True);
1632 yn_popup = XtCreatePopupShell("query", transientShellWidgetClass,
1633 toplevel, args, ONE);
1634 XtOverrideTranslations(yn_popup,
1635 XtParseTranslationTable("<Message>WM_PROTOCOLS: yn_delete()"));
1638 XtSetArg(args[num_args], XtNtranslations,
1639 XtParseTranslationTable(yn_translations)); num_args++;
1640 yn_label = XtCreateManagedWidget("yn_label",
1645 XtRealizeWidget(yn_popup);
1646 XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup),
1647 &wm_delete_window, 1);
1650 if(appResources.slow)
1651 input_func = yn_key;
1654 XtSetArg(args[num_args], XtNlabel, buf); num_args++;
1655 XtSetValues(yn_label, args, num_args);
1657 if(!appResources.slow) {
1659 * Due to some kind of weird bug in the X11R4 and X11R5 shell, we
1660 * need to set the label twice to get the size to change.
1663 XtSetArg(args[num_args], XtNlabel, buf); num_args++;
1664 XtSetValues(yn_label, args, num_args);
1666 positionpopup(yn_popup, TRUE);
1667 nh_XtPopup(yn_popup, (int)XtGrabExclusive, yn_label);
1670 yn_getting_num = FALSE;
1671 (void) x_event(EXIT_ON_EXIT);
1673 if(appResources.slow) {
1676 XtSetArg(args[num_args], XtNlabel, " "); num_args++;
1677 XtSetValues(yn_label, args, num_args);
1679 nh_XtPopdown(yn_popup); /* this removes the event grab */
1685 /* End global functions ==================================================== */
1688 * Before we wait for input via nhgetch() and nh_poskey(), we need to
1689 * do some pre-processing.
1692 input_event(exit_condition)
1695 if (WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */
1696 check_turn_events();
1697 if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */
1698 check_cursor_visibility(&window_list[WIN_MAP]);
1699 if (WIN_MESSAGE != WIN_ERR) /* reset pause line */
1700 set_last_pause(&window_list[WIN_MESSAGE]);
1702 return x_event(exit_condition);
1708 msgkey(w, data, event)
1714 map_input(window_list[WIN_MAP].w, event, (String*) 0, &num);
1719 win_visible(w, data, event, flag) /* only called for autofocus */
1721 XtPointer data; /* client_data not used */
1723 Boolean *flag; /* continue_to_dispatch flag not used */
1725 XVisibilityEvent *vis_event = (XVisibilityEvent *)event;
1727 if (vis_event->state != VisibilityFullyObscured) {
1728 /* one-time operation; cancel ourself */
1729 XtRemoveEventHandler(toplevel, VisibilityChangeMask, False,
1730 win_visible, (XtPointer) 0);
1731 /* grab initial input focus */
1732 XSetInputFocus(XtDisplay(w), XtWindow(w), RevertToNone, CurrentTime);
1737 * Set up the playing console. This has three major parts: the
1738 * message window, the map, and the status window.
1741 init_standard_windows()
1743 Widget form, message_viewport, map_viewport, status;
1746 Dimension message_vp_width, map_vp_width, status_width, max_width;
1747 int map_vp_hd, status_hd;
1752 XtSetArg(args[num_args], XtNallowShellResize, True); num_args++;
1753 form = XtCreateManagedWidget("nethack",
1755 toplevel, args, num_args);
1757 XtAddEventHandler(form, KeyPressMask, False,
1758 (XtEventHandler) msgkey, (XtPointer) 0);
1760 if (appResources.autofocus)
1761 XtAddEventHandler(toplevel, VisibilityChangeMask, False,
1762 win_visible, (XtPointer) 0);
1765 * Create message window.
1767 WIN_MESSAGE = message_win = find_free_window();
1768 wp = &window_list[message_win];
1769 wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
1770 wp->popup = (Widget) 0;
1771 create_message_window(wp, FALSE, form);
1772 message_viewport = XtParent(wp->w);
1775 /* Tell the form that contains it that resizes are OK. */
1777 XtSetArg(args[num_args], XtNresizable, True); num_args++;
1778 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
1779 XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++;
1780 XtSetValues(message_viewport, args, num_args);
1782 if(appResources.slow) {
1784 XtSetArg(args[num_args], XtNtranslations,
1785 XtParseTranslationTable(yn_translations)); num_args++;
1786 yn_label = XtCreateManagedWidget("yn_label",
1791 XtSetArg(args[num_args], XtNfromVert, message_viewport); num_args++;
1792 XtSetArg(args[num_args], XtNjustify, XtJustifyLeft); num_args++;
1793 XtSetArg(args[num_args], XtNresizable, True); num_args++;
1794 XtSetArg(args[num_args], XtNlabel, " "); num_args++;
1795 XtSetValues(yn_label, args, num_args);
1799 * Create the map window & viewport and chain the viewport beneath the
1802 map_win = find_free_window();
1803 wp = &window_list[map_win];
1804 wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
1805 wp->popup = (Widget) 0;
1806 create_map_window(wp, FALSE, form);
1807 map_viewport = XtParent(wp->w);
1809 /* Chain beneath message_viewport or yn window. */
1811 if(appResources.slow) {
1812 XtSetArg(args[num_args], XtNfromVert, yn_label); num_args++;
1814 XtSetArg(args[num_args], XtNfromVert, message_viewport);num_args++;
1816 XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++;
1817 XtSetValues(map_viewport, args, num_args);
1819 /* Create the status window, with the form as it's parent. */
1820 status_win = find_free_window();
1821 wp = &window_list[status_win];
1822 wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0;
1823 wp->popup = (Widget) 0;
1824 create_status_window(wp, FALSE, form);
1828 * Chain the status window beneath the viewport. Mark the left and right
1829 * edges so that they stay a fixed distance from the left edge of the
1830 * parent, as well as the top and bottom edges so that they stay a fixed
1831 * distance from the bottom of the parent. We do this so that the status
1832 * will never expand or contract.
1835 XtSetArg(args[num_args], XtNfromVert, map_viewport); num_args++;
1836 XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++;
1837 XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++;
1838 XtSetArg(args[num_args], XtNtop, XtChainBottom); num_args++;
1839 XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++;
1840 XtSetValues(status, args, num_args);
1844 * Realize the popup so that the status widget knows it's size.
1846 * If we unset MappedWhenManaged then the DECwindow driver doesn't
1847 * attach the nethack toplevel to the highest virtual root window.
1850 /* XtSetMappedWhenManaged(toplevel, False); */
1851 XtRealizeWidget(toplevel);
1852 wm_delete_window = XInternAtom(XtDisplay(toplevel),
1853 "WM_DELETE_WINDOW", False);
1854 XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel),
1855 &wm_delete_window, 1);
1858 * Resize to at most full-screen.
1861 #define TITLEBAR_SPACE 18 /* Leave SOME screen for window decorations */
1863 int screen_width = WidthOfScreen(XtScreen(wp->w));
1864 int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE;
1865 Dimension form_width, form_height;
1867 XtSetArg(args[0], XtNwidth, &form_width);
1868 XtSetArg(args[1], XtNheight, &form_height);
1869 XtGetValues(toplevel, args, TWO);
1871 if (form_width > screen_width || form_height > screen_height) {
1872 XtSetArg(args[0], XtNwidth, min(form_width,screen_width));
1873 XtSetArg(args[1], XtNheight, min(form_height,screen_height));
1874 XtSetValues(toplevel, args, TWO);
1875 XMoveWindow(XtDisplay(toplevel),XtWindow(toplevel),
1878 #undef TITLEBAR_SPACE
1881 post_process_tiles(); /* after toplevel is realized */
1884 * Now get the default widths of the windows.
1886 XtSetArg(args[0], XtNwidth, &message_vp_width);
1887 XtGetValues(message_viewport, args, ONE);
1888 XtSetArg(args[0], XtNwidth, &map_vp_width);
1889 XtSetArg(args[1], XtNhorizDistance, &map_vp_hd);
1890 XtGetValues(map_viewport, args, TWO);
1891 XtSetArg(args[0], XtNwidth, &status_width);
1892 XtSetArg(args[1], XtNhorizDistance, &status_hd);
1893 XtGetValues(status, args, TWO);
1896 * Adjust positions and sizes. The message viewport widens out to the
1897 * widest width. Both the map and status are centered by adjusting
1898 * their horizDistance.
1900 if (map_vp_width < status_width || map_vp_width < message_vp_width) {
1901 if (status_width > message_vp_width) {
1902 XtSetArg(args[0], XtNwidth, status_width);
1903 XtSetValues(message_viewport, args, ONE);
1904 max_width = status_width;
1906 /***** The status display looks better when left justified.
1907 XtSetArg(args[0], XtNhorizDistance,
1908 status_hd+((message_vp_width-status_width)/2));
1909 XtSetValues(status, args, ONE);
1911 max_width = message_vp_width;
1913 XtSetArg(args[0], XtNhorizDistance, map_vp_hd+((int)(max_width-map_vp_width)/2));
1914 XtSetValues(map_viewport, args, ONE);
1916 } else { /* map is widest */
1917 XtSetArg(args[0], XtNwidth, map_vp_width);
1918 XtSetValues(message_viewport, args, ONE);
1920 /***** The status display looks better when left justified.
1921 XtSetArg(args[0], XtNhorizDistance,
1922 status_hd+((map_vp_width-status_width)/2));
1924 XtSetValues(status, args, ONE);
1928 * Clear all data values on the fancy status widget so that the values
1929 * used for spacing don't appear. This needs to be called some time
1930 * after the fancy status widget is realized (above, with the game popup),
1931 * but before it is popped up.
1935 * Set the map size to its standard size. As with the message window
1936 * above, the map window needs to be set to its constrained size until
1937 * its parent (the viewport widget) was realized.
1939 * Move the message window's slider to the bottom.
1941 set_map_size(&window_list[map_win], COLNO, ROWNO);
1942 set_message_slider(&window_list[message_win]);
1944 /* attempt to catch fatal X11 errors before the program quits */
1945 (void) XtAppSetErrorHandler(app_context, (XtErrorHandler) hangup);
1947 /* We can now print to the message window. */
1948 iflags.window_inited = 1;
1953 nh_XtPopup(w, g, childwid)
1954 Widget w; /* widget */
1955 int g; /* type of grab */
1956 Widget childwid; /* child to recieve focus (can be None) */
1958 XtPopup(w, (XtGrabKind)g);
1959 XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1);
1960 if (appResources.autofocus) XtSetKeyboardFocus(toplevel, childwid);
1968 if (appResources.autofocus) XtSetKeyboardFocus(toplevel, None);
1975 /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these
1976 * two routines will not be found when linking. An apparently correct
1977 * executable is produced, along with nasty messages and a failure code
1978 * returned to make. The routines are in the static libXmu.a and
1979 * libXmu.sa.4.0, but not in libXmu.so.4.0. Rather than fiddle with
1980 * static linking, we do this.
1983 /* i.e., FALSE that an optimizer probably can't find */
1984 get_wmShellWidgetClass();
1985 get_applicationShellWidgetClass();
1992 * Scroll a viewport, using standard NH 1,2,3,4,6,7,8,9 directions.
1996 nh_keyscroll(viewport, event, params, num_params)
2000 Cardinal *num_params;
2003 Widget horiz_sb, vert_sb;
2007 Cardinal in_nparams = (num_params ? *num_params : 0);
2009 if (in_nparams != 1) return; /* bad translation */
2011 direction=atoi(params[0]);
2013 horiz_sb = XtNameToWidget(viewport, "*horizontal");
2014 vert_sb = XtNameToWidget(viewport, "*vertical");
2016 if (!horiz_sb && !vert_sb) {
2017 /* Perhaps the widget enclosing this has scrollbars (could use while) */
2018 Widget parent=XtParent(viewport);
2020 horiz_sb = XtNameToWidget(parent, "horizontal");
2021 vert_sb = XtNameToWidget(parent, "vertical");
2025 #define H_DELTA 0.25 /* distance of horiz shift */
2026 /* vert shift is half of curr distance */
2027 /* The V_DELTA is 1/2 the value of shown. */
2030 XtSetArg(arg[0], XtNshown, &shown);
2031 XtSetArg(arg[1], XtNtopOfThumb, &top);
2032 XtGetValues(horiz_sb, arg, TWO);
2036 switch (direction) {
2037 case 1: case 4: case 7:
2039 if (top < 0.0) top = 0.0;
2040 break; case 3: case 6: case 9:
2042 if (top + shown > 1.0) top = 1.0 - shown;
2048 XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
2053 XtSetArg(arg[0], XtNshown, &shown);
2054 XtSetArg(arg[1], XtNtopOfThumb, &top);
2055 XtGetValues(vert_sb, arg, TWO);
2059 switch (direction) {
2060 case 7: case 8: case 9:
2062 if (top < 0.0) top = 0;
2063 break; case 1: case 2: case 3:
2065 if (top + shown > 1.0) top = 1.0 - shown;
2071 XtCallCallbacks(vert_sb, XtNjumpProc, &top);