1 /* NetHack 3.6 gnbind.c $NHDT-Date: 1450453305 2015/12/18 15:41:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.33 $ */
2 /* Copyright (C) 1998 by Erik Andersen <andersee@debian.org> */
3 /* NetHack may be freely redistributed. See license for details. */
6 * This file implements the interface between the window port specific
7 * code in the Gnome port and the rest of the nethack game engine.
16 GNHWinData gnome_windowlist
[MAXWINDOWS
];
17 winid WIN_WORN
= WIN_ERR
;
19 extern void tty_raw_print(const char *);
20 extern void tty_raw_print_bold(const char *);
22 /* this is only needed until gnome_status_* routines are written */
23 extern NEARDATA winid WIN_STATUS
;
25 /* Interface definition, for windows.c */
26 struct window_procs Gnome_procs
= {
27 "Gnome", WC_COLOR
| WC_HILITE_PET
| WC_INVERSE
, 0L, gnome_init_nhwindows
,
28 gnome_player_selection
, gnome_askname
, gnome_get_nh_event
,
29 gnome_exit_nhwindows
, gnome_suspend_nhwindows
, gnome_resume_nhwindows
,
30 gnome_create_nhwindow
, gnome_clear_nhwindow
, gnome_display_nhwindow
,
31 gnome_destroy_nhwindow
, gnome_curs
, gnome_putstr
, genl_putmixed
,
32 gnome_display_file
, gnome_start_menu
, gnome_add_menu
, gnome_end_menu
,
34 genl_message_menu
, /* no need for X-specific handling */
35 gnome_update_inventory
, gnome_mark_synch
, gnome_wait_synch
,
42 gnome_print_glyph
, gnome_raw_print
, gnome_raw_print_bold
, gnome_nhgetch
,
43 gnome_nh_poskey
, gnome_nhbell
, gnome_doprev_message
, gnome_yn_function
,
44 gnome_getlin
, gnome_get_ext_cmd
, gnome_number_pad
, gnome_delay_output
,
45 #ifdef CHANGE_COLOR /* only a Mac option currently */
48 /* other defs that really should go away (they're tty specific) */
49 gnome_start_screen
, gnome_end_screen
, gnome_outrip
,
50 genl_preference_update
, genl_getmsghistory
, genl_putmsghistory
,
51 #ifdef STATUS_VIA_WINDOWPORT
52 genl_status_init
, genl_status_finish
, genl_status_enablefield
,
55 genl_status_threshold
,
62 init_nhwindows(int* argcp, char** argv)
63 -- Initialize the windows used by NetHack. This can also
64 create the standard windows listed at the top, but does
66 -- Any commandline arguments relevant to the windowport
67 should be interpreted, and *argcp and *argv should
68 be changed to remove those arguments.
69 -- When the message window is created, the variable
70 iflags.window_inited needs to be set to TRUE. Otherwise
71 all plines() will be done via raw_print().
72 ** Why not have init_nhwindows() create all of the "standard"
73 ** windows? Or at least all but WIN_INFO? -dean
76 gnome_init_nhwindows(int *argc
, char **argv
)
79 ghack_init_main_window(*argc
, argv
);
83 // if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm"))
84 if (ghack_init_glyphs(HACKDIR
"/x11tiles"))
85 g_error("ERROR: Could not initialize glyphs.\n");
87 #error HACKDIR is not defined!
90 // gnome/gtk is not reentrant
91 set_option_mod_status("ignintr", DISP_IN_GAME
);
94 iflags
.window_inited
= TRUE
;
96 /* gnome-specific window creation */
97 WIN_WORN
= gnome_create_nhwindow(NHW_WORN
);
100 /* Do a window-port specific player type selection. If player_selection()
101 offers a Quit option, it is its responsibility to clean up and terminate
102 the process. You need to fill in pl_character[0].
105 gnome_player_selection()
108 const char **choices
;
111 /* prevent an unnecessary prompt */
114 if (!flags
.randomall
&& flags
.initrole
< 0) {
116 for (n
= 0; roles
[n
].name
.m
; n
++)
118 choices
= (const char **) alloc(sizeof(char *) * (n
+ 1));
119 pickmap
= (int *) alloc(sizeof(int) * (n
+ 1));
121 for (n
= 0, i
= 0; roles
[i
].name
.m
; i
++) {
122 if (ok_role(i
, flags
.initrace
, flags
.initgend
,
124 if (flags
.initgend
>= 0 && flags
.female
126 choices
[n
] = roles
[i
].name
.f
;
128 choices
[n
] = roles
[i
].name
.m
;
134 else if (flags
.initalign
>= 0)
135 flags
.initalign
= -1; /* reset */
136 else if (flags
.initgend
>= 0)
138 else if (flags
.initrace
>= 0)
141 panic("no available ROLE+race+gender+alignment combinations");
143 choices
[n
] = (const char *) 0;
145 sel
= ghack_player_sel_dialog(
146 choices
, _("Player selection"),
147 _("Choose one of the following roles:"));
152 else if (sel
== ROLE_NONE
) { /* Quit */
158 } else if (flags
.initrole
< 0)
161 sel
= flags
.initrole
;
163 if (sel
== ROLE_RANDOM
) { /* Random role */
164 sel
= pick_role(flags
.initrace
, flags
.initgend
, flags
.initalign
,
170 flags
.initrole
= sel
;
172 /* Select a race, if necessary */
173 /* force compatibility with role, try for compatibility with
174 * pre-selected gender/alignment */
175 if (flags
.initrace
< 0 || !validrace(flags
.initrole
, flags
.initrace
)) {
176 if (flags
.initrace
== ROLE_RANDOM
|| flags
.randomall
) {
177 flags
.initrace
= pick_race(flags
.initrole
, flags
.initgend
,
178 flags
.initalign
, PICK_RANDOM
);
179 if (flags
.initrace
< 0)
180 flags
.initrace
= randrace(flags
.initrole
);
182 /* Count the number of valid races */
183 n
= 0; /* number valid */
184 for (i
= 0; races
[i
].noun
; i
++) {
185 if (ok_race(flags
.initrole
, i
, flags
.initgend
,
190 for (i
= 0; races
[i
].noun
; i
++) {
191 if (validrace(flags
.initrole
, i
))
196 choices
= (const char **) alloc(sizeof(char *) * (n
+ 1));
197 pickmap
= (int *) alloc(sizeof(int) * (n
+ 1));
198 for (n
= 0, i
= 0; races
[i
].noun
; i
++) {
199 if (ok_race(flags
.initrole
, i
, flags
.initgend
,
201 choices
[n
] = races
[i
].noun
;
205 choices
[n
] = (const char *) 0;
206 /* Permit the user to pick, if there is more than one */
208 sel
= ghack_player_sel_dialog(
209 choices
, _("Race selection"),
210 _("Choose one of the following races:"));
215 else if (sel
== ROLE_NONE
) { /* Quit */
219 flags
.initrace
= sel
;
223 if (flags
.initrace
== ROLE_RANDOM
) { /* Random role */
224 sel
= pick_race(flags
.initrole
, flags
.initgend
, flags
.initalign
,
227 sel
= randrace(flags
.initrole
);
228 flags
.initrace
= sel
;
232 /* Select a gender, if necessary */
233 /* force compatibility with role/race, try for compatibility with
234 * pre-selected alignment */
235 if (flags
.initgend
< 0
236 || !validgend(flags
.initrole
, flags
.initrace
, flags
.initgend
)) {
237 if (flags
.initgend
== ROLE_RANDOM
|| flags
.randomall
) {
238 flags
.initgend
= pick_gend(flags
.initrole
, flags
.initrace
,
239 flags
.initalign
, PICK_RANDOM
);
240 if (flags
.initgend
< 0)
241 flags
.initgend
= randgend(flags
.initrole
, flags
.initrace
);
243 /* Count the number of valid genders */
244 n
= 0; /* number valid */
245 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
246 if (ok_gend(flags
.initrole
, flags
.initrace
, i
,
251 for (i
= 0; i
< ROLE_GENDERS
; i
++) {
252 if (validgend(flags
.initrole
, flags
.initrace
, i
))
257 choices
= (const char **) alloc(sizeof(char *) * (n
+ 1));
258 pickmap
= (int *) alloc(sizeof(int) * (n
+ 1));
259 for (n
= 0, i
= 0; i
< ROLE_GENDERS
; i
++) {
260 if (ok_gend(flags
.initrole
, flags
.initrace
, i
,
262 choices
[n
] = genders
[i
].adj
;
266 choices
[n
] = (const char *) 0;
267 /* Permit the user to pick, if there is more than one */
269 sel
= ghack_player_sel_dialog(
270 choices
, _("Gender selection"),
271 _("Choose one of the following genders:"));
276 else if (sel
== ROLE_NONE
) { /* Quit */
280 flags
.initgend
= sel
;
284 if (flags
.initgend
== ROLE_RANDOM
) { /* Random gender */
285 sel
= pick_gend(flags
.initrole
, flags
.initrace
, flags
.initalign
,
288 sel
= randgend(flags
.initrole
, flags
.initrace
);
289 flags
.initgend
= sel
;
293 /* Select an alignment, if necessary */
294 /* force compatibility with role/race/gender */
295 if (flags
.initalign
< 0
296 || !validalign(flags
.initrole
, flags
.initrace
, flags
.initalign
)) {
297 if (flags
.initalign
== ROLE_RANDOM
|| flags
.randomall
) {
298 flags
.initalign
= pick_align(flags
.initrole
, flags
.initrace
,
299 flags
.initgend
, PICK_RANDOM
);
300 if (flags
.initalign
< 0)
301 flags
.initalign
= randalign(flags
.initrole
, flags
.initrace
);
303 /* Count the number of valid alignments */
304 n
= 0; /* number valid */
305 for (i
= 0; i
< ROLE_ALIGNS
; i
++) {
306 if (ok_align(flags
.initrole
, flags
.initrace
, flags
.initgend
,
311 for (i
= 0; i
< ROLE_ALIGNS
; i
++)
312 if (validalign(flags
.initrole
, flags
.initrace
, i
))
316 choices
= (const char **) alloc(sizeof(char *) * (n
+ 1));
317 pickmap
= (int *) alloc(sizeof(int) * (n
+ 1));
318 for (n
= 0, i
= 0; i
< ROLE_ALIGNS
; i
++) {
319 if (ok_align(flags
.initrole
, flags
.initrace
, flags
.initgend
,
321 choices
[n
] = aligns
[i
].adj
;
325 choices
[n
] = (const char *) 0;
326 /* Permit the user to pick, if there is more than one */
328 sel
= ghack_player_sel_dialog(
329 choices
, _("Alignment selection"),
330 _("Choose one of the following alignments:"));
335 else if (sel
== ROLE_NONE
) { /* Quit */
339 flags
.initalign
= sel
;
343 if (flags
.initalign
== ROLE_RANDOM
) {
344 sel
= pick_align(flags
.initrole
, flags
.initrace
, flags
.initgend
,
347 sel
= randalign(flags
.initrole
, flags
.initrace
);
348 flags
.initalign
= sel
;
353 /* Ask the user for a player name. */
359 g_message("Asking name....");
361 /* Ask for a name and stuff the response into plname, a nethack global */
362 ret
= ghack_ask_string_dialog("What is your name?", "gandalf",
363 "GnomeHack", plname
);
365 /* Quit if they want to quit... */
372 /* Does window event processing (e.g. exposure events).
373 A noop for the tty and X window-ports.
378 /* We handle our own events. */
382 /* Exits the window system. This should dismiss all windows,
383 except the "window" used for raw_print(). str is printed if possible.
386 gnome_exit_nhwindows(const char *str
)
388 /* gtk cannot do this without exiting the program, do nothing */
391 /* Prepare the window to be suspended. */
393 gnome_suspend_nhwindows(const char *str
)
395 /* I don't think we need to do anything here... */
399 /* Restore the windows after being suspended. */
401 gnome_resume_nhwindows()
403 /* Do Nothing. Un-necessary since the GUI will refresh itself. */
407 /* Create a window of type "type" which can be
408 NHW_MESSAGE (top line)
409 NHW_STATUS (bottom lines)
410 NHW_MAP (main dungeon)
411 NHW_MENU (inventory or other "corner" windows)
412 NHW_TEXT (help/text, full screen paged window)
415 gnome_create_nhwindow(int type
)
419 /* Return the next available winid */
421 for (i
= 0; i
< MAXWINDOWS
; i
++)
422 if (gnome_windowlist
[i
].win
== NULL
)
425 g_error("ERROR: No windows available...\n");
426 gnome_create_nhwindow_by_id(type
, i
);
431 gnome_create_nhwindow_by_id(int type
, winid i
)
435 gnome_windowlist
[i
].win
= ghack_init_map_window();
436 gnome_windowlist
[i
].type
= NHW_MAP
;
437 ghack_main_window_add_map_window(gnome_windowlist
[i
].win
);
441 gnome_windowlist
[i
].win
= ghack_init_message_window();
442 gnome_windowlist
[i
].type
= NHW_MESSAGE
;
443 ghack_main_window_add_message_window(gnome_windowlist
[i
].win
);
447 gnome_windowlist
[i
].win
= ghack_init_status_window();
448 gnome_windowlist
[i
].type
= NHW_STATUS
;
449 ghack_main_window_add_status_window(gnome_windowlist
[i
].win
);
453 gnome_windowlist
[i
].win
= ghack_init_worn_window();
454 gnome_windowlist
[i
].type
= NHW_WORN
;
455 ghack_main_window_add_worn_window(gnome_windowlist
[i
].win
);
459 gnome_windowlist
[i
].type
= NHW_MENU
;
460 gnome_windowlist
[i
].win
= ghack_init_menu_window();
464 gnome_windowlist
[i
].win
= ghack_init_text_window();
465 gnome_windowlist
[i
].type
= NHW_TEXT
;
471 /* This widget is being destroyed before its time--
472 * clear its entry from the windowlist.
475 gnome_delete_nhwindow_by_reference(GtkWidget
*menuWin
)
479 for (i
= 0; i
< MAXWINDOWS
; i
++) {
480 if (gnome_windowlist
[i
].win
== menuWin
) {
481 gnome_windowlist
[i
].win
= NULL
;
482 gnome_windowlist
[i
].type
= 0;
488 /* Clear the given window, when asked to. */
490 gnome_clear_nhwindow(winid wid
)
492 if (gnome_windowlist
[wid
].win
!= NULL
) {
493 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
494 ghack_signals
[GHSIG_CLEAR
]);
498 /* -- Display the window on the screen. If there is data
499 pending for output in that window, it should be sent.
500 If blocking is TRUE, display_nhwindow() will not
501 return until the data has been displayed on the screen,
502 and acknowledged by the user where appropriate.
503 -- All calls are blocking in the tty window-port.
504 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
505 --more--, if necessary, in the tty window-port.
508 gnome_display_nhwindow(winid wid
, BOOLEAN_P block
)
510 if (gnome_windowlist
[wid
].win
!= NULL
) {
511 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
512 ghack_signals
[GHSIG_DISPLAY
], block
);
513 if (block
&& (gnome_windowlist
[wid
].type
== NHW_MAP
))
514 (void) gnome_nhgetch();
518 /* Destroy will dismiss the window if the window has not
519 * already been dismissed.
522 gnome_destroy_nhwindow(winid wid
)
524 if ((wid
== WIN_MAP
) || (wid
== WIN_MESSAGE
) || (wid
== WIN_STATUS
)) {
525 /* no thanks, I'll do these myself */
528 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
) {
529 gtk_widget_destroy(gnome_windowlist
[wid
].win
);
530 gnome_windowlist
[wid
].win
= NULL
;
531 gnome_windowlist
[wid
].type
= 0;
535 /* Next output to window will start at (x,y), also moves
536 displayable cursor to (x,y). For backward compatibility,
537 1 <= x < cols, 0 <= y < rows, where cols and rows are
541 gnome_curs(winid wid
, int x
, int y
)
543 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
) {
544 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
545 ghack_signals
[GHSIG_CURS
], x
, y
);
550 putstr(window, attr, str)
551 -- Print str on the window with the given attribute. Only
552 printable ASCII characters (040-0126) must be supported.
553 Multiple putstr()s are output on separate lines.
561 If a window-port does not support all of these, it may map
562 unsupported attributes to a supported one (e.g. map them
563 all to ATR_INVERSE). putstr() may compress spaces out of
564 str, break str, or truncate str, if necessary for the
565 display. Where putstr() breaks a line, it has to clear
567 -- putstr should be implemented such that if two putstr()s
568 are done consecutively the user will see the first and
569 then the second. In the tty port, pline() achieves this
570 by calling more() or displaying both on the same line.
573 gnome_putstr(winid wid
, int attr
, const char *text
)
575 if ((wid
>= 0) && (wid
< MAXWINDOWS
)
576 && (gnome_windowlist
[wid
].win
!= NULL
)) {
577 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
578 ghack_signals
[GHSIG_PUTSTR
], (guint
) attr
, text
);
582 /* Display the file named str. Complain about missing files
583 iff complain is TRUE.
586 gnome_display_file(const char *filename
, BOOLEAN_P must_exist
)
588 /* Strange -- for some reason it makes us create a new text window
589 * instead of reusing any existing ones -- perhaps we can work out
590 * some way to reuse stuff -- but for now just make and destroy new
595 f
= dlb_fopen(filename
, "r");
600 sprintf(message
, "Warning! Could not find file: %s\n", filename
);
602 box
= gnome_message_box_new(_(message
), GNOME_MESSAGE_BOX_ERROR
,
603 GNOME_STOCK_BUTTON_OK
, NULL
);
604 gnome_dialog_set_default(GNOME_DIALOG(box
), 0);
605 gnome_dialog_set_parent(GNOME_DIALOG(box
),
606 GTK_WINDOW(ghack_get_main_window()));
607 gtk_window_set_modal(GTK_WINDOW(box
), TRUE
);
608 gtk_widget_show(box
);
611 GtkWidget
*txtwin
, *gless
, *frametxt
;
613 char line
[LLEN
], *textlines
;
614 int num_lines
, charcount
;
616 txtwin
= gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK
, NULL
);
617 gtk_widget_set_usize(GTK_WIDGET(txtwin
), 500, 400);
618 gtk_window_set_policy(GTK_WINDOW(txtwin
), TRUE
, TRUE
, FALSE
);
619 gtk_window_set_title(GTK_WINDOW(txtwin
), "Text Window");
620 gnome_dialog_set_default(GNOME_DIALOG(txtwin
), 0);
621 gtk_window_set_modal(GTK_WINDOW(txtwin
), TRUE
);
622 frametxt
= gtk_frame_new("");
623 gtk_widget_show(frametxt
);
626 * Count the number of lines and characters in the file.
630 while (dlb_fgets(line
, LLEN
, f
)) {
632 charcount
+= strlen(line
);
634 (void) dlb_fclose(f
);
636 /* Ignore empty files */
641 * Re-open the file and read the data into a buffer.
643 textlines
= (char *) alloc((unsigned int) charcount
);
645 f
= dlb_fopen(filename
, RDTMODE
);
647 while (dlb_fgets(line
, LLEN
, f
)) {
648 (void) strcat(textlines
, line
);
650 (void) dlb_fclose(f
);
652 gless
= gnome_less_new();
653 gnome_less_show_string(GNOME_LESS(gless
), textlines
);
654 gtk_container_add(GTK_CONTAINER(frametxt
), gless
);
655 gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(txtwin
)->vbox
), frametxt
,
657 gtk_widget_show_all(txtwin
);
658 gtk_window_set_modal(GTK_WINDOW(txtwin
), TRUE
);
659 gnome_dialog_set_parent(GNOME_DIALOG(txtwin
),
660 GTK_WINDOW(ghack_get_main_window()));
661 gnome_dialog_run_and_close(GNOME_DIALOG(txtwin
));
666 /* Start using window as a menu. You must call start_menu()
667 before add_menu(). After calling start_menu() you may not
668 putstr() to the window. Only windows of type NHW_MENU may
672 gnome_start_menu(winid wid
)
675 if (gnome_windowlist
[wid
].win
== NULL
676 && gnome_windowlist
[wid
].type
!= 0) {
677 gnome_create_nhwindow_by_id(gnome_windowlist
[wid
].type
, wid
);
679 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
680 ghack_signals
[GHSIG_START_MENU
]);
685 add_menu(windid window, int glyph, const anything identifier,
686 char accelerator, char groupacc,
687 int attr, char *str, boolean preselected)
688 -- Add a text line str to the given menu window. If
690 is 0, then the line cannot be selected (e.g. a title).
691 Otherwise, identifier is the value returned if the line is
692 selected. Accelerator is a keyboard key that can be used
693 to select the line. If the accelerator of a selectable
694 item is 0, the window system is free to select its own
695 accelerator. It is up to the window-port to make the
696 accelerator visible to the user (e.g. put "a - " in front
697 of str). The value attr is the same as in putstr().
698 Glyph is an optional glyph to accompany the line. If
699 window port cannot or does not want to display it, this
700 is OK. If there is no glyph applicable, then this
701 value will be NO_GLYPH.
702 -- All accelerators should be in the range [A-Za-z].
703 -- It is expected that callers do not mix accelerator
704 choices. Either all selectable items have an accelerator
705 or let the window system pick them. Don't do both.
706 -- Groupacc is a group accelerator. It may be any character
707 outside of the standard accelerator (see above) or a
708 number. If 0, the item is unaffected by any group
709 accelerator. If this accelerator conflicts with
710 the menu command (or their user defined alises), it loses.
711 The menu commands and aliases take care not to interfere
712 with the default object class symbols.
713 -- If you want this choice to be preselected when the
714 menu is displayed, set preselected to TRUE.
717 gnome_add_menu(winid wid
, int glyph
, const ANY_P
*identifier
,
718 CHAR_P accelerator
, CHAR_P group_accel
, int attr
,
719 const char *str
, BOOLEAN_P presel
)
723 item
.identifier
= identifier
;
724 item
.accelerator
= accelerator
;
725 item
.group_accel
= group_accel
;
728 item
.presel
= presel
;
730 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
) {
731 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
732 ghack_signals
[GHSIG_ADD_MENU
], &item
);
737 end_menu(window, prompt)
738 -- Stop adding entries to the menu and flushes the window
739 to the screen (brings to front?). Prompt is a prompt
740 to give the user. If prompt is NULL, no prompt will
742 ** This probably shouldn't flush the window any more (if
743 ** it ever did). That should be select_menu's job. -dean
746 gnome_end_menu(winid wid
, const char *prompt
)
748 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
) {
749 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
750 ghack_signals
[GHSIG_END_MENU
], prompt
);
755 int select_menu(windid window, int how, menu_item **selected)
756 -- Return the number of items selected; 0 if none were chosen,
757 -1 when explicitly cancelled. If items were selected, then
758 selected is filled in with an allocated array of menu_item
759 structures, one for each selected line. The caller must
760 free this array when done with it. The "count" field
761 of selected is a user supplied count. If the user did
762 not supply a count, then the count field is filled with
763 -1 (meaning all). A count of zero is equivalent to not
764 being selected and should not be in the list. If no items
765 were selected, then selected is NULL'ed out. How is the
766 mode of the menu. Three valid values are PICK_NONE,
767 PICK_ONE, and PICK_N, meaning: nothing is selectable,
768 only one thing is selectable, and any number valid items
769 may selected. If how is PICK_NONE, this function should
770 never return anything but 0 or -1.
771 -- You may call select_menu() on a window multiple times --
772 the menu is saved until start_menu() or destroy_nhwindow()
773 is called on the window.
774 -- Note that NHW_MENU windows need not have select_menu()
775 called for them. There is no way of knowing whether
776 select_menu() will be called for the window at
777 create_nhwindow() time.
780 gnome_select_menu(winid wid
, int how
, MENU_ITEM_P
**selected
)
784 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
785 && gnome_windowlist
[wid
].type
== NHW_MENU
) {
786 nReturned
= ghack_menu_window_select_menu(gnome_windowlist
[wid
].win
,
794 -- Indicate to the window port that the inventory has been changed.
795 -- Merely calls display_inventory() for window-ports that leave the
796 window up, otherwise empty.
799 gnome_update_inventory()
801 ghack_main_window_update_inventory();
805 mark_synch() -- Don't go beyond this point in I/O on any channel until
806 all channels are caught up to here. Can be an empty call
816 wait_synch() -- Wait until all pending output is complete (*flush*() for
818 -- May also deal with exposure events etc. so that the
819 display is OK when return from wait_synch().
828 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
829 screen if the playing area is larger than the screen.
830 -- This function is only defined if CLIPPING is defined.
833 gnome_cliparound(int x
, int y
)
835 /* FIXME!!! winid should be a parameter!!!
836 * Call a function that Does The Right Thing(tm).
838 gnome_cliparound_proper(WIN_MAP
, x
, y
);
842 gnome_cliparound_proper(winid wid
, int x
, int y
)
844 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
) {
845 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
846 ghack_signals
[GHSIG_CLIPAROUND
], (guint
) x
,
852 print_glyph(window, x, y, glyph, bkglyph)
853 -- Print the glyph at (x,y) on the given window. Glyphs are
854 integers at the interface, mapped to whatever the window-
855 port wants (symbol, font, color, attributes, ...there's
856 a 1-1 map between glyphs and distinct things on the map).
859 gnome_print_glyph(winid wid
, XCHAR_P x
, XCHAR_P y
, int glyph
, int bkglyph
)
861 if (wid
!= -1 && gnome_windowlist
[wid
].win
!= NULL
) {
864 im
= ghack_image_from_glyph(glyph
, FALSE
);
866 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[wid
].win
),
867 ghack_signals
[GHSIG_PRINT_GLYPH
], (guint
) x
,
868 (guint
) y
, im
, NULL
);
873 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
874 the user sees str. raw_print() appends a newline to str.
875 It need not recognize ASCII control characters. This is
876 used during startup (before windowing system initialization
877 -- maybe this means only error startup messages are raw),
878 for error messages, and maybe other "msg" uses. E.g.
879 updating status for micros (i.e, "saving").
882 gnome_raw_print(const char *str
)
889 -- Like raw_print(), but prints in bold/standout (if
893 gnome_raw_print_bold(const char *str
)
895 tty_raw_print_bold(str
);
899 int nhgetch() -- Returns a single character input from the user.
900 -- In the tty window-port, nhgetch() assumes that tgetch()
901 will be the routine the OS provides to read a character.
902 Returned character _must_ be non-zero.
909 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[WIN_STATUS
].win
),
910 ghack_signals
[GHSIG_FADE_HIGHLIGHT
]);
912 g_askingQuestion
= 1;
913 /* Process events until a key press event arrives. */
914 while (g_numKeys
== 0) {
915 if (program_state
.done_hup
)
917 gtk_main_iteration();
920 theFirst
= g_list_first(g_keyBuffer
);
921 g_keyBuffer
= g_list_remove_link(g_keyBuffer
, theFirst
);
922 key
= GPOINTER_TO_INT(theFirst
->data
);
923 g_list_free_1(theFirst
);
925 g_askingQuestion
= 0;
930 int nh_poskey(int *x, int *y, int *mod)
931 -- Returns a single character input from the user or a
932 a positioning event (perhaps from a mouse). If the
933 return value is non-zero, a character was typed, else,
934 a position in the MAP window is returned in x, y and mod.
937 CLICK_1 -- mouse click type 1
938 CLICK_2 -- mouse click type 2
940 The different click types can map to whatever the
941 hardware supports. If no mouse is supported, this
942 routine always returns a non-zero character.
945 gnome_nh_poskey(int *x
, int *y
, int *mod
)
947 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[WIN_STATUS
].win
),
948 ghack_signals
[GHSIG_FADE_HIGHLIGHT
]);
950 g_askingQuestion
= 0;
951 /* Process events until a key or map-click arrives. */
952 while (g_numKeys
== 0 && g_numClicks
== 0) {
953 if (program_state
.done_hup
)
955 gtk_main_iteration();
962 theFirst
= g_list_first(g_keyBuffer
);
963 g_keyBuffer
= g_list_remove_link(g_keyBuffer
, theFirst
);
964 key
= GPOINTER_TO_INT(theFirst
->data
);
965 g_list_free_1(theFirst
);
972 theFirst
= g_list_first(g_clickBuffer
);
973 g_clickBuffer
= g_list_remove_link(g_clickBuffer
, theFirst
);
974 click
= (GHClick
*) theFirst
->data
;
979 g_list_free_1(theFirst
);
986 nhbell() -- Beep at user. [This will exist at least until sounds are
987 redone, since sounds aren't attributable to windows
993 /* FIXME!!! Play a cool GNOME sound instead */
999 -- Display previous messages. Used by the ^P command.
1000 -- On the tty-port this scrolls WIN_MESSAGE back one line.
1003 gnome_doprev_message()
1005 /* Do Nothing. They can read old messages using the scrollbar. */
1010 char yn_function(const char *ques, const char *choices, char default)
1011 -- Print a prompt made up of ques, choices and default.
1012 Read a single character response that is contained in
1013 choices or default. If choices is NULL, all possible
1014 inputs are accepted and returned. This overrides
1015 everything else. The choices are expected to be in
1016 lower case. Entering ESC always maps to 'q', or 'n',
1017 in that order, if present in choices, otherwise it maps
1018 to default. Entering any other quit character (SPACE,
1019 RETURN, NEWLINE) maps to default.
1020 -- If the choices string contains ESC, then anything after
1021 it is an acceptable response, but the ESC and whatever
1022 follows is not included in the prompt.
1023 -- If the choices string contains a '#' then accept a count.
1024 Place this value in the global "yn_number" and return '#'.
1025 -- This uses the top line in the tty window-port, other
1026 ports might use a popup.
1029 gnome_yn_function(const char *question
, const char *choices
, CHAR_P def
)
1033 char message
[BUFSZ
];
1034 char yn_esc_map
= '\033';
1035 GtkWidget
*mainWnd
= ghack_get_main_window();
1038 char *cb
, choicebuf
[QBUFSZ
];
1039 Strcpy(choicebuf
, choices
);
1040 if ((cb
= index(choicebuf
, '\033')) != 0) {
1041 /* anything beyond <esc> is hidden */
1044 (void) strncpy(message
, question
, QBUFSZ
- 1);
1045 message
[QBUFSZ
- 1] = '\0';
1046 sprintf(eos(message
), " [%s]", choicebuf
);
1048 sprintf(eos(message
), " (%c)", def
);
1049 Strcat(message
, " ");
1050 /* escape maps to 'q' or 'n' or default, in that order */
1052 (index(choices
, 'q') ? 'q' : (index(choices
, 'n') ? 'n' : def
));
1054 Strcpy(message
, question
);
1057 gnome_putstr(WIN_MESSAGE
, ATR_BOLD
, message
);
1058 if (mainWnd
!= NULL
&& choices
&& !index(choices
, ch
)) {
1059 return (ghack_yes_no_dialog(question
, choices
, def
));
1062 /* Only here if main window is not present */
1063 while (result
< 0) {
1064 ch
= gnome_nhgetch();
1066 result
= yn_esc_map
;
1067 } else if (choices
&& !index(choices
, ch
)) {
1068 /* FYI: ch==-115 is for KP_ENTER */
1070 && (ch
== ' ' || ch
== '\r' || ch
== '\n' || ch
== -115)) {
1074 /* and try again... */
1084 getlin(const char *ques, char *input)
1085 -- Prints ques as a prompt and reads a single line of text,
1086 up to a newline. The string entered is returned without the
1087 newline. ESC is used to cancel, in which case the string
1088 "\033\000" is returned.
1089 -- getlin() must call flush_screen(1) before doing anything.
1090 -- This uses the top line in the tty window-port, other
1091 ports might use a popup.
1094 gnome_getlin(const char *question
, char *input
)
1098 ret
= ghack_ask_string_dialog(question
, "", "nethack", input
);
1105 int get_ext_cmd(void)
1106 -- Get an extended command in a window-port specific way.
1107 An index into extcmdlist[] is returned on a successful
1108 selection, -1 otherwise.
1113 return ghack_menu_ext_cmd();
1118 -- Initialize the number pad to the given state.
1121 gnome_number_pad(int state
)
1127 delay_output() -- Causes a visible delay of 50ms in the output.
1128 Conceptually, this is similar to wait_synch() followed
1129 by a nap(50ms), but allows asynchronous operation.
1132 gnome_delay_output()
1134 if (gnome_windowlist
[WIN_MESSAGE
].win
!= NULL
) {
1135 gtk_signal_emit(GTK_OBJECT(gnome_windowlist
[WIN_MESSAGE
].win
),
1136 ghack_signals
[GHSIG_DELAY
], (guint
) 50);
1141 start_screen() -- Only used on Unix tty ports, but must be declared for
1142 completeness. Sets up the tty to work in full-screen
1143 graphics mode. Look at win/tty/termcap.c for an
1144 example. If your window-port does not need this function
1145 just declare an empty function.
1148 gnome_start_screen()
1154 end_screen() -- Only used on Unix tty ports, but must be declared for
1155 completeness. The complement of start_screen().
1164 outrip(winid, int, when)
1165 -- The tombstone code. If you want the traditional code use
1166 genl_outrip for the value and check the #if in rip.c.
1169 gnome_outrip(winid wid
, int how
, time_t when
)
1171 /* Follows roughly the same algorithm as genl_outrip() */
1173 char ripString
[BUFSZ
] = "\0";
1176 /* Put name on stone */
1177 Sprintf(buf
, "%s\n", plname
);
1178 Strcat(ripString
, buf
);
1180 /* Put $ on stone */
1181 Sprintf(buf
, "%ld Au\n", done_money
);
1182 Strcat(ripString
, buf
);
1184 /* Put together death description */
1185 formatkiller(buf
, sizeof buf
, how
, FALSE
);
1187 /* Put death type on stone */
1188 Strcat(ripString
, buf
);
1189 Strcat(ripString
, "\n");
1191 /* Put year on stone */
1192 year
= yyyymmdd(when
) / 10000L;
1193 Sprintf(buf
, "%4ld\n", year
);
1194 Strcat(ripString
, buf
);
1196 ghack_text_window_rip_string(ripString
);