1 /* SCCS Id: @(#)gnbind.c 3.4 2000/07/16 */
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 *);
23 /* Interface definition, for windows.c */
24 struct window_procs Gnome_procs = {
26 WC_COLOR|WC_HILITE_PET|WC_INVERSE,
29 gnome_player_selection,
33 gnome_suspend_nhwindows,
34 gnome_resume_nhwindows,
35 gnome_create_nhwindow,
37 gnome_display_nhwindow,
38 gnome_destroy_nhwindow,
46 genl_message_menu, /* no need for X-specific handling */
47 gnome_update_inventory,
68 #ifdef CHANGE_COLOR /* only a Mac option currently */
72 /* other defs that really should go away (they're tty specific) */
76 genl_preference_update,
80 init_nhwindows(int* argcp, char** argv)
81 -- Initialize the windows used by NetHack. This can also
82 create the standard windows listed at the top, but does
84 -- Any commandline arguments relevant to the windowport
85 should be interpreted, and *argcp and *argv should
86 be changed to remove those arguments.
87 -- When the message window is created, the variable
88 iflags.window_inited needs to be set to TRUE. Otherwise
89 all plines() will be done via raw_print().
90 ** Why not have init_nhwindows() create all of the "standard"
91 ** windows? Or at least all but WIN_INFO? -dean
93 void gnome_init_nhwindows(int* argc, char** argv)
96 ghack_init_main_window( *argc, argv);
97 ghack_init_signals( );
100 //if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm"))
101 if (ghack_init_glyphs(HACKDIR "/x11tiles"))
102 g_error ("ERROR: Could not initialize glyphs.\n");
104 # error HACKDIR is not defined!
107 // gnome/gtk is not reentrant
108 set_option_mod_status("ignintr", DISP_IN_GAME);
109 flags.ignintr = TRUE;
111 iflags.window_inited = TRUE;
113 /* gnome-specific window creation */
114 WIN_WORN = gnome_create_nhwindow(NHW_WORN);
118 /* Do a window-port specific player type selection. If player_selection()
119 offers a Quit option, it is its responsibility to clean up and terminate
120 the process. You need to fill in pl_character[0].
123 gnome_player_selection()
126 const char** choices;
129 /* prevent an unnecessary prompt */
132 if (!flags.randomall && flags.initrole < 0) {
135 for (n = 0; roles[n].name.m; n++) continue;
136 choices = (const char **)alloc(sizeof(char *) * (n+1));
137 pickmap = (int*)alloc(sizeof(int) * (n+1));
139 for (n = 0, i = 0; roles[i].name.m; i++) {
140 if (ok_role(i, flags.initrace,
141 flags.initgend, flags.initalign)) {
142 if (flags.initgend >= 0 && flags.female && roles[i].name.f)
143 choices[n] = roles[i].name.f;
145 choices[n] = roles[i].name.m;
150 else if (flags.initalign >= 0) flags.initalign = -1; /* reset */
151 else if (flags.initgend >= 0) flags.initgend = -1;
152 else if (flags.initrace >= 0) flags.initrace = -1;
153 else panic("no available ROLE+race+gender+alignment combinations");
155 choices[n] = (const char *) 0;
157 sel = ghack_player_sel_dialog(choices,
158 _("Player selection"), _("Choose one of the following roles:"));
160 if (sel >= 0) sel = pickmap[sel];
161 else if (sel == ROLE_NONE) { /* Quit */
163 gnome_exit_nhwindows(0);
167 } else if (flags.initrole < 0) sel = ROLE_RANDOM;
168 else sel = flags.initrole;
170 if (sel == ROLE_RANDOM) { /* Random role */
171 sel = pick_role(flags.initrace, flags.initgend,
172 flags.initalign, PICK_RANDOM);
173 if (sel < 0) sel = randrole();
176 flags.initrole = sel;
178 /* Select a race, if necessary */
179 /* force compatibility with role, try for compatibility with
180 * pre-selected gender/alignment */
181 if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) {
182 if (flags.initrace == ROLE_RANDOM || flags.randomall) {
183 flags.initrace = pick_race(flags.initrole, flags.initgend,
184 flags.initalign, PICK_RANDOM);
185 if (flags.initrace < 0) flags.initrace = randrace(flags.initrole);
187 /* Count the number of valid races */
188 n = 0; /* number valid */
189 for (i = 0; races[i].noun; i++) {
190 if (ok_race(flags.initrole, i, flags.initgend, flags.initalign))
194 for (i = 0; races[i].noun; i++) {
195 if (validrace(flags.initrole, i)) n++;
199 choices = (const char **)alloc(sizeof(char *) * (n+1));
200 pickmap = (int*)alloc(sizeof(int) * (n + 1));
201 for (n = 0, i = 0; races[i].noun; i++) {
202 if (ok_race(flags.initrole, i, flags.initgend,
204 choices[n] = races[i].noun;
208 choices[n] = (const char *) 0;
209 /* Permit the user to pick, if there is more than one */
211 sel = ghack_player_sel_dialog(choices, _("Race selection"),
212 _("Choose one of the following races:"));
214 if (sel >= 0) sel = pickmap[sel];
215 else if (sel == ROLE_NONE) { /* Quit */
217 gnome_exit_nhwindows(0);
219 flags.initrace = sel;
223 if (flags.initrace == ROLE_RANDOM) { /* Random role */
224 sel = pick_race(flags.initrole, flags.initgend,
225 flags.initalign, PICK_RANDOM);
226 if (sel < 0) sel = randrace(flags.initrole);
227 flags.initrace = sel;
231 /* Select a gender, if necessary */
232 /* force compatibility with role/race, try for compatibility with
233 * pre-selected alignment */
234 if (flags.initgend < 0 ||
235 !validgend(flags.initrole, flags.initrace, flags.initgend)) {
236 if (flags.initgend == ROLE_RANDOM || flags.randomall) {
237 flags.initgend = pick_gend(flags.initrole, flags.initrace,
238 flags.initalign, PICK_RANDOM);
239 if (flags.initgend < 0)
240 flags.initgend = randgend(flags.initrole, flags.initrace);
242 /* Count the number of valid genders */
243 n = 0; /* number valid */
244 for (i = 0; i < ROLE_GENDERS; i++) {
245 if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign))
249 for (i = 0; i < ROLE_GENDERS; i++) {
250 if (validgend(flags.initrole, flags.initrace, i)) n++;
254 choices = (const char **)alloc(sizeof(char *) * (n+1));
255 pickmap = (int*)alloc(sizeof(int) * (n + 1));
256 for (n = 0, i = 0; i < ROLE_GENDERS; i++) {
257 if (ok_gend(flags.initrole, flags.initrace, i,
259 choices[n] = genders[i].adj;
263 choices[n] = (const char *) 0;
264 /* Permit the user to pick, if there is more than one */
266 sel = ghack_player_sel_dialog(choices, _("Gender selection"),
267 _("Choose one of the following genders:"));
269 if (sel >= 0) sel = pickmap[sel];
270 else if (sel == ROLE_NONE) { /* Quit */
272 gnome_exit_nhwindows(0);
274 flags.initgend = sel;
278 if (flags.initgend == ROLE_RANDOM) { /* Random gender */
279 sel = pick_gend(flags.initrole, flags.initrace,
280 flags.initalign, PICK_RANDOM);
281 if (sel < 0) sel = randgend(flags.initrole, flags.initrace);
282 flags.initgend = sel;
286 /* Select an alignment, if necessary */
287 /* force compatibility with role/race/gender */
288 if (flags.initalign < 0 ||
289 !validalign(flags.initrole, flags.initrace, flags.initalign)) {
290 if (flags.initalign == ROLE_RANDOM || flags.randomall) {
291 flags.initalign = pick_align(flags.initrole, flags.initrace,
292 flags.initgend, PICK_RANDOM);
293 if (flags.initalign < 0)
294 flags.initalign = randalign(flags.initrole, flags.initrace);
296 /* Count the number of valid alignments */
297 n = 0; /* number valid */
298 for (i = 0; i < ROLE_ALIGNS; i++) {
299 if (ok_align(flags.initrole, flags.initrace, flags.initgend, i))
303 for (i = 0; i < ROLE_ALIGNS; i++)
304 if (validalign(flags.initrole, flags.initrace, i)) n++;
307 choices = (const char **)alloc(sizeof(char *) * (n+1));
308 pickmap = (int*)alloc(sizeof(int) * (n + 1));
309 for (n = 0, i = 0; i < ROLE_ALIGNS; i++) {
310 if (ok_align(flags.initrole,
311 flags.initrace, flags.initgend, i)) {
312 choices[n] = aligns[i].adj;
316 choices[n] = (const char *) 0;
317 /* Permit the user to pick, if there is more than one */
319 sel = ghack_player_sel_dialog(choices, _("Alignment selection"),
320 _("Choose one of the following alignments:"));
322 if (sel >= 0) sel = pickmap[sel];
323 else if (sel == ROLE_NONE) { /* Quit */
325 gnome_exit_nhwindows(0);
327 flags.initalign = sel;
331 if (flags.initalign == ROLE_RANDOM) {
332 sel = pick_align(flags.initrole, flags.initrace,
333 flags.initgend, PICK_RANDOM);
334 if (sel < 0) sel = randalign(flags.initrole, flags.initrace);
335 flags.initalign = sel;
341 /* Ask the user for a player name. */
346 g_message("Asking name....");
348 /* Ask for a name and stuff the response into plname, a nethack global */
349 ret = ghack_ask_string_dialog("What is your name?", "gandalf",
350 "GnomeHack", plname);
352 /* Quit if they want to quit... */
355 gnome_exit_nhwindows(0);
360 /* Does window event processing (e.g. exposure events).
361 A noop for the tty and X window-ports.
363 void gnome_get_nh_event()
365 /* We handle our own events. */
369 /* Exits the window system. This should dismiss all windows,
370 except the "window" used for raw_print(). str is printed if possible.
372 void gnome_exit_nhwindows(const char *str)
375 terminate(EXIT_SUCCESS);
378 /* Prepare the window to be suspended. */
379 void gnome_suspend_nhwindows(const char *str)
381 /* I don't think we need to do anything here... */
386 /* Restore the windows after being suspended. */
387 void gnome_resume_nhwindows()
389 /* Do Nothing. Un-necessary since the GUI will refresh itself. */
393 /* Create a window of type "type" which can be
394 NHW_MESSAGE (top line)
395 NHW_STATUS (bottom lines)
396 NHW_MAP (main dungeon)
397 NHW_MENU (inventory or other "corner" windows)
398 NHW_TEXT (help/text, full screen paged window)
401 gnome_create_nhwindow(int type)
406 /* Return the next available winid
409 for (i=0; i<MAXWINDOWS; i++)
410 if (gnome_windowlist[i].win == NULL)
413 g_error ("ERROR: No windows available...\n");
414 gnome_create_nhwindow_by_id( type, i);
419 gnome_create_nhwindow_by_id( int type, winid i)
425 gnome_windowlist[i].win = ghack_init_map_window( );
426 gnome_windowlist[i].type = NHW_MAP;
427 ghack_main_window_add_map_window( gnome_windowlist[i].win);
432 gnome_windowlist[i].win = ghack_init_message_window( );
433 gnome_windowlist[i].type = NHW_MESSAGE;
434 ghack_main_window_add_message_window( gnome_windowlist[i].win);
439 gnome_windowlist[i].win = ghack_init_status_window( );
440 gnome_windowlist[i].type = NHW_STATUS;
441 ghack_main_window_add_status_window( gnome_windowlist[i].win);
446 gnome_windowlist[i].win = ghack_init_worn_window( );
447 gnome_windowlist[i].type = NHW_WORN;
448 ghack_main_window_add_worn_window(gnome_windowlist[i].win);
453 gnome_windowlist[i].type = NHW_MENU;
454 gnome_windowlist[i].win = ghack_init_menu_window( );
459 gnome_windowlist[i].win = ghack_init_text_window( );
460 gnome_windowlist[i].type = NHW_TEXT;
466 /* This widget is being destroyed before its time--
467 * clear its entry from the windowlist.
469 void gnome_delete_nhwindow_by_reference( GtkWidget *menuWin)
473 for (i = 0; i < MAXWINDOWS; i++) {
474 if (gnome_windowlist[i].win == menuWin) {
475 gnome_windowlist[i].win = NULL;
476 gnome_windowlist[i].type = 0;
482 /* Clear the given window, when asked to. */
483 void gnome_clear_nhwindow(winid wid)
485 if (gnome_windowlist[wid].win != NULL)
487 gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win),
488 ghack_signals[GHSIG_CLEAR]);
492 /* -- Display the window on the screen. If there is data
493 pending for output in that window, it should be sent.
494 If blocking is TRUE, display_nhwindow() will not
495 return until the data has been displayed on the screen,
496 and acknowledged by the user where appropriate.
497 -- All calls are blocking in the tty window-port.
498 -- Calling display_nhwindow(WIN_MESSAGE,???) will do a
499 --more--, if necessary, in the tty window-port.
501 void gnome_display_nhwindow(winid wid, BOOLEAN_P block)
503 if (gnome_windowlist[wid].win != NULL)
505 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
506 ghack_signals[GHSIG_DISPLAY],
508 if (block && (gnome_windowlist[wid].type == NHW_MAP))
509 (void) gnome_nhgetch();
514 /* Destroy will dismiss the window if the window has not
515 * already been dismissed.
517 void gnome_destroy_nhwindow(winid wid)
519 if ((wid == WIN_MAP) ||
520 (wid == WIN_MESSAGE) ||
521 (wid == WIN_STATUS)) {
522 /* no thanks, I'll do these myself */
525 if (wid != -1 && gnome_windowlist[wid].win != NULL)
527 gtk_widget_destroy(gnome_windowlist[wid].win);
528 gnome_windowlist[wid].win = NULL;
529 gnome_windowlist[wid].type = 0;
533 /* Next output to window will start at (x,y), also moves
534 displayable cursor to (x,y). For backward compatibility,
535 1 <= x < cols, 0 <= y < rows, where cols and rows are
538 void gnome_curs(winid wid, int x, int y)
540 if (wid != -1 && gnome_windowlist[wid].win != NULL)
542 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
543 ghack_signals[GHSIG_CURS], x, y);
548 putstr(window, attr, str)
549 -- Print str on the window with the given attribute. Only
550 printable ASCII characters (040-0126) must be supported.
551 Multiple putstr()s are output on separate lines.
559 If a window-port does not support all of these, it may map
560 unsupported attributes to a supported one (e.g. map them
561 all to ATR_INVERSE). putstr() may compress spaces out of
562 str, break str, or truncate str, if necessary for the
563 display. Where putstr() breaks a line, it has to clear
565 -- putstr should be implemented such that if two putstr()s
566 are done consecutively the user will see the first and
567 then the second. In the tty port, pline() achieves this
568 by calling more() or displaying both on the same line.
570 void gnome_putstr(winid wid, int attr, const char *text)
573 (wid < MAXWINDOWS) &&
574 (gnome_windowlist[wid].win != NULL))
576 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
577 ghack_signals[GHSIG_PUTSTR],
583 /* Display the file named str. Complain about missing files
584 iff complain is TRUE.
586 void 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),
603 GNOME_MESSAGE_BOX_ERROR,
604 GNOME_STOCK_BUTTON_OK,
606 gnome_dialog_set_default( GNOME_DIALOG(box), 0);
607 gnome_dialog_set_parent (GNOME_DIALOG (box),
608 GTK_WINDOW (ghack_get_main_window ()) );
609 gtk_window_set_modal( GTK_WINDOW(box), TRUE);
610 gtk_widget_show (box);
614 GtkWidget *txtwin, *gless, *frametxt;
616 char line[LLEN], *textlines;
617 int num_lines, charcount;
619 txtwin = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK,
621 gtk_widget_set_usize(GTK_WIDGET(txtwin), 500, 400);
622 gtk_window_set_policy(GTK_WINDOW(txtwin), TRUE, TRUE, FALSE);
623 gtk_window_set_title(GTK_WINDOW(txtwin), "Text Window");
624 gnome_dialog_set_default( GNOME_DIALOG(txtwin), 0);
625 gtk_window_set_modal( GTK_WINDOW(txtwin), TRUE);
626 frametxt = gtk_frame_new ("");
627 gtk_widget_show (frametxt);
630 * Count the number of lines and characters in the file.
634 while (dlb_fgets(line, LLEN, f)) {
636 charcount += strlen(line);
638 (void) dlb_fclose(f);
640 /* Ignore empty files */
641 if (num_lines == 0) return;
644 * Re-open the file and read the data into a buffer.
646 textlines = (char *) alloc((unsigned int) charcount);
648 f = dlb_fopen( filename, RDTMODE);
650 while (dlb_fgets(line, LLEN, f)) {
651 (void) strcat(textlines, line);
653 (void) dlb_fclose(f);
655 gless = gnome_less_new ();
656 gnome_less_show_string (GNOME_LESS (gless), textlines);
657 gtk_container_add (GTK_CONTAINER (frametxt), gless);
658 gtk_box_pack_start(GTK_BOX (GNOME_DIALOG (txtwin)->vbox), frametxt,
660 gtk_widget_show_all( txtwin);
661 gtk_window_set_modal( GTK_WINDOW(txtwin), TRUE);
662 gnome_dialog_set_parent (GNOME_DIALOG (txtwin),
663 GTK_WINDOW (ghack_get_main_window ()) );
664 gnome_dialog_run_and_close (GNOME_DIALOG (txtwin));
669 /* Start using window as a menu. You must call start_menu()
670 before add_menu(). After calling start_menu() you may not
671 putstr() to the window. Only windows of type NHW_MENU may
674 void gnome_start_menu(winid wid)
678 if (gnome_windowlist[wid].win == NULL && gnome_windowlist[wid].type != 0)
680 gnome_create_nhwindow_by_id(gnome_windowlist[wid].type, wid);
682 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
683 ghack_signals[GHSIG_START_MENU]);
688 add_menu(windid window, int glyph, const anything identifier,
689 char accelerator, char groupacc,
690 int attr, char *str, boolean preselected)
691 -- Add a text line str to the given menu window. If identifier
692 is 0, then the line cannot be selected (e.g. a title).
693 Otherwise, identifier is the value returned if the line is
694 selected. Accelerator is a keyboard key that can be used
695 to select the line. If the accelerator of a selectable
696 item is 0, the window system is free to select its own
697 accelerator. It is up to the window-port to make the
698 accelerator visible to the user (e.g. put "a - " in front
699 of str). The value attr is the same as in putstr().
700 Glyph is an optional glyph to accompany the line. If
701 window port cannot or does not want to display it, this
702 is OK. If there is no glyph applicable, then this
703 value will be NO_GLYPH.
704 -- All accelerators should be in the range [A-Za-z].
705 -- It is expected that callers do not mix accelerator
706 choices. Either all selectable items have an accelerator
707 or let the window system pick them. Don't do both.
708 -- Groupacc is a group accelerator. It may be any character
709 outside of the standard accelerator (see above) or a
710 number. If 0, the item is unaffected by any group
711 accelerator. If this accelerator conflicts with
712 the menu command (or their user defined alises), it loses.
713 The menu commands and aliases take care not to interfere
714 with the default object class symbols.
715 -- If you want this choice to be preselected when the
716 menu is displayed, set preselected to TRUE.
718 void gnome_add_menu(winid wid, int glyph, const ANY_P * identifier,
719 CHAR_P accelerator, CHAR_P group_accel, int attr,
720 const char *str, BOOLEAN_P presel)
724 item.identifier = identifier;
725 item.accelerator = accelerator;
726 item.group_accel = group_accel;
729 item.presel = presel;
731 if (wid != -1 && gnome_windowlist[wid].win != NULL)
733 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
734 ghack_signals[GHSIG_ADD_MENU],
740 end_menu(window, prompt)
741 -- Stop adding entries to the menu and flushes the window
742 to the screen (brings to front?). Prompt is a prompt
743 to give the user. If prompt is NULL, no prompt will
745 ** This probably shouldn't flush the window any more (if
746 ** it ever did). That should be select_menu's job. -dean
748 void gnome_end_menu(winid wid, const char *prompt)
750 if (wid != -1 && gnome_windowlist[wid].win != NULL)
752 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
753 ghack_signals[GHSIG_END_MENU],
759 int select_menu(windid window, int how, menu_item **selected)
760 -- Return the number of items selected; 0 if none were chosen,
761 -1 when explicitly cancelled. If items were selected, then
762 selected is filled in with an allocated array of menu_item
763 structures, one for each selected line. The caller must
764 free this array when done with it. The "count" field
765 of selected is a user supplied count. If the user did
766 not supply a count, then the count field is filled with
767 -1 (meaning all). A count of zero is equivalent to not
768 being selected and should not be in the list. If no items
769 were selected, then selected is NULL'ed out. How is the
770 mode of the menu. Three valid values are PICK_NONE,
771 PICK_ONE, and PICK_N, meaning: nothing is selectable,
772 only one thing is selectable, and any number valid items
773 may selected. If how is PICK_NONE, this function should
774 never return anything but 0 or -1.
775 -- You may call select_menu() on a window multiple times --
776 the menu is saved until start_menu() or destroy_nhwindow()
777 is called on the window.
778 -- Note that NHW_MENU windows need not have select_menu()
779 called for them. There is no way of knowing whether
780 select_menu() will be called for the window at
781 create_nhwindow() time.
783 int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected)
787 if (wid != -1 && gnome_windowlist[wid].win != NULL &&
788 gnome_windowlist[wid].type == NHW_MENU)
790 nReturned=ghack_menu_window_select_menu (gnome_windowlist[wid].win,
798 -- Indicate to the window port that the inventory has been changed.
799 -- Merely calls display_inventory() for window-ports that leave the
800 window up, otherwise empty.
802 void gnome_update_inventory()
804 ghack_main_window_update_inventory();
808 mark_synch() -- Don't go beyond this point in I/O on any channel until
809 all channels are caught up to here. Can be an empty call
812 void gnome_mark_synch()
818 wait_synch() -- Wait until all pending output is complete (*flush*() for
820 -- May also deal with exposure events etc. so that the
821 display is OK when return from wait_synch().
823 void gnome_wait_synch()
829 cliparound(x, y)-- Make sure that the user is more-or-less centered on the
830 screen if the playing area is larger than the screen.
831 -- This function is only defined if CLIPPING is defined.
833 void 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);
841 void gnome_cliparound_proper(winid wid, int x, int y)
843 if (wid != -1 && gnome_windowlist[wid].win != NULL)
845 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
846 ghack_signals[GHSIG_CLIPAROUND],
853 print_glyph(window, x, y, glyph)
854 -- Print the glyph at (x,y) on the given window. Glyphs are
855 integers at the interface, mapped to whatever the window-
856 port wants (symbol, font, color, attributes, ...there's
857 a 1-1 map between glyphs and distinct things on the map).
859 void gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
861 if (wid != -1 && gnome_windowlist[wid].win != NULL)
865 im = ghack_image_from_glyph( glyph, FALSE);
867 gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win),
868 ghack_signals[GHSIG_PRINT_GLYPH],
877 raw_print(str) -- Print directly to a screen, or otherwise guarantee that
878 the user sees str. raw_print() appends a newline to str.
879 It need not recognize ASCII control characters. This is
880 used during startup (before windowing system initialization
881 -- maybe this means only error startup messages are raw),
882 for error messages, and maybe other "msg" uses. E.g.
883 updating status for micros (i.e, "saving").
885 void gnome_raw_print(const char *str)
892 -- Like raw_print(), but prints in bold/standout (if
895 void gnome_raw_print_bold(const char *str)
897 tty_raw_print_bold(str);
901 int nhgetch() -- Returns a single character input from the user.
902 -- In the tty window-port, nhgetch() assumes that tgetch()
903 will be the routine the OS provides to read a character.
904 Returned character _must_ be non-zero.
910 gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win),
911 ghack_signals[GHSIG_FADE_HIGHLIGHT]);
913 g_askingQuestion = 1;
914 /* Process events until a key press event arrives. */
915 while ( g_numKeys == 0 )
916 gtk_main_iteration();
918 theFirst = g_list_first( g_keyBuffer);
919 g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst);
920 key = GPOINTER_TO_INT( theFirst->data);
921 g_list_free_1( theFirst);
923 g_askingQuestion = 0;
928 int nh_poskey(int *x, int *y, int *mod)
929 -- Returns a single character input from the user or a
930 a positioning event (perhaps from a mouse). If the
931 return value is non-zero, a character was typed, else,
932 a position in the MAP window is returned in x, y and mod.
935 CLICK_1 -- mouse click type 1
936 CLICK_2 -- mouse click type 2
938 The different click types can map to whatever the
939 hardware supports. If no mouse is supported, this
940 routine always returns a non-zero character.
942 int gnome_nh_poskey(int *x, int *y, int *mod)
944 gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win),
945 ghack_signals[GHSIG_FADE_HIGHLIGHT]);
947 g_askingQuestion = 0;
948 /* Process events until a key or map-click arrives. */
949 while ( g_numKeys == 0 && g_numClicks == 0 )
950 gtk_main_iteration();
956 theFirst = g_list_first( g_keyBuffer);
957 g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst);
958 key = GPOINTER_TO_INT( theFirst->data);
959 g_list_free_1( theFirst);
967 theFirst = g_list_first( g_clickBuffer);
968 g_clickBuffer = g_list_remove_link(g_clickBuffer, theFirst);
969 click = (GHClick*) theFirst->data;
974 g_list_free_1( theFirst);
981 nhbell() -- Beep at user. [This will exist at least until sounds are
982 redone, since sounds aren't attributable to windows anyway.]
986 /* FIXME!!! Play a cool GNOME sound instead */
992 -- Display previous messages. Used by the ^P command.
993 -- On the tty-port this scrolls WIN_MESSAGE back one line.
995 int gnome_doprev_message()
997 /* Do Nothing. They can read old messages using the scrollbar. */
1002 char yn_function(const char *ques, const char *choices, char default)
1003 -- Print a prompt made up of ques, choices and default.
1004 Read a single character response that is contained in
1005 choices or default. If choices is NULL, all possible
1006 inputs are accepted and returned. This overrides
1007 everything else. The choices are expected to be in
1008 lower case. Entering ESC always maps to 'q', or 'n',
1009 in that order, if present in choices, otherwise it maps
1010 to default. Entering any other quit character (SPACE,
1011 RETURN, NEWLINE) maps to default.
1012 -- If the choices string contains ESC, then anything after
1013 it is an acceptable response, but the ESC and whatever
1014 follows is not included in the prompt.
1015 -- If the choices string contains a '#' then accept a count.
1016 Place this value in the global "yn_number" and return '#'.
1017 -- This uses the top line in the tty window-port, other
1018 ports might use a popup.
1020 char gnome_yn_function(const char *question, const char *choices,
1025 char message[BUFSZ];
1026 char yn_esc_map='\033';
1027 GtkWidget *mainWnd = ghack_get_main_window();
1031 char *cb, choicebuf[QBUFSZ];
1032 Strcpy(choicebuf, choices);
1033 if ((cb = index(choicebuf, '\033')) != 0) {
1034 /* anything beyond <esc> is hidden */
1037 sprintf(message, "%s [%s] ", question, choicebuf);
1038 if (def) sprintf(eos(message), "(%c) ", def);
1039 /* escape maps to 'q' or 'n' or default, in that order */
1040 yn_esc_map = (index(choices, 'q') ? 'q' :
1041 (index(choices, 'n') ? 'n' : def));
1043 Strcpy(message, question);
1047 gnome_putstr(WIN_MESSAGE, ATR_BOLD, message);
1048 if (mainWnd != NULL && choices && !index(choices,ch)) {
1049 return(ghack_yes_no_dialog( question, choices, def));
1052 /* Only here if main window is not present */
1057 } else if (choices && !index(choices,ch)) {
1058 /* FYI: ch==-115 is for KP_ENTER */
1059 if (def && (ch==' ' || ch=='\r' || ch=='\n' || ch==-115)) {
1063 /* and try again... */
1073 getlin(const char *ques, char *input)
1074 -- Prints ques as a prompt and reads a single line of text,
1075 up to a newline. The string entered is returned without the
1076 newline. ESC is used to cancel, in which case the string
1077 "\033\000" is returned.
1078 -- getlin() must call flush_screen(1) before doing anything.
1079 -- This uses the top line in the tty window-port, other
1080 ports might use a popup.
1082 void gnome_getlin(const char *question, char *input)
1086 ret = ghack_ask_string_dialog(question, "", "nethack", input);
1093 int get_ext_cmd(void)
1094 -- Get an extended command in a window-port specific way.
1095 An index into extcmdlist[] is returned on a successful
1096 selection, -1 otherwise.
1098 int gnome_get_ext_cmd()
1100 return ghack_menu_ext_cmd();
1106 -- Initialize the number pad to the given state.
1108 void gnome_number_pad(int state)
1114 delay_output() -- Causes a visible delay of 50ms in the output.
1115 Conceptually, this is similar to wait_synch() followed
1116 by a nap(50ms), but allows asynchronous operation.
1118 void gnome_delay_output()
1120 if (gnome_windowlist[WIN_MESSAGE].win != NULL) {
1121 gtk_signal_emit( GTK_OBJECT (gnome_windowlist[WIN_MESSAGE].win),
1122 ghack_signals[GHSIG_DELAY],
1128 start_screen() -- Only used on Unix tty ports, but must be declared for
1129 completeness. Sets up the tty to work in full-screen
1130 graphics mode. Look at win/tty/termcap.c for an
1131 example. If your window-port does not need this function
1132 just declare an empty function.
1134 void gnome_start_screen()
1140 end_screen() -- Only used on Unix tty ports, but must be declared for
1141 completeness. The complement of start_screen().
1143 void gnome_end_screen()
1150 -- The tombstone code. If you want the traditional code use
1151 genl_outrip for the value and check the #if in rip.c.
1153 void gnome_outrip(winid wid, int how)
1155 /* Follows roughly the same algorithm as genl_outrip() */
1157 char ripString[BUFSZ]="\0";
1158 extern const char *killed_by_prefix[];
1160 /* Put name on stone */
1161 Sprintf(buf, "%s\n", plname);
1162 Strcat(ripString, buf);
1164 /* Put $ on stone */
1165 Sprintf(buf, "%ld Au\n",
1171 Strcat(ripString, buf);
1173 /* Put together death description */
1174 switch (killer_format) {
1175 default: impossible("bad killer format?");
1177 Strcpy(buf, killed_by_prefix[how]);
1178 Strcat(buf, an(killer));
1181 Strcpy(buf, killed_by_prefix[how]);
1182 Strcat(buf, killer);
1184 case NO_KILLER_PREFIX:
1185 Strcpy(buf, killer);
1188 /* Put death type on stone */
1189 Strcat(ripString, buf);
1190 Strcat(ripString, "\n");
1192 /* Put year on stone */
1193 Sprintf(buf, "%4d\n", getyear());
1194 Strcat(ripString, buf);
1196 ghack_text_window_rip_string( ripString);