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. */
4 
5 /*
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.
8 */
9 
10 #include "gnbind.h"
11 #include "gnmain.h"
12 #include "gnmenu.h"
13 #include "gnaskstr.h"
14 #include "gnyesno.h"
15 
16 GNHWinData gnome_windowlist[MAXWINDOWS];
17 winid WIN_WORN = WIN_ERR;
18 
19 extern void tty_raw_print(const char *);
20 extern void tty_raw_print_bold(const char *);
21 
22 
23 /* Interface definition, for windows.c */
24 struct window_procs Gnome_procs = {
25     "Gnome",
26     WC_COLOR|WC_HILITE_PET|WC_INVERSE,
27     0L,
28     gnome_init_nhwindows,
29     gnome_player_selection,
30     gnome_askname,
31     gnome_get_nh_event,
32     gnome_exit_nhwindows,
33     gnome_suspend_nhwindows,
34     gnome_resume_nhwindows,
35     gnome_create_nhwindow,
36     gnome_clear_nhwindow,
37     gnome_display_nhwindow,
38     gnome_destroy_nhwindow,
39     gnome_curs,
40     gnome_putstr,
41     gnome_display_file,
42     gnome_start_menu,
43     gnome_add_menu,
44     gnome_end_menu,
45     gnome_select_menu,
46     genl_message_menu,		/* no need for X-specific handling */
47     gnome_update_inventory,
48     gnome_mark_synch,
49     gnome_wait_synch,
50 #ifdef CLIPPING
51     gnome_cliparound,
52 #endif
53 #ifdef POSITIONBAR
54     donull,
55 #endif
56     gnome_print_glyph,
57     gnome_raw_print,
58     gnome_raw_print_bold,
59     gnome_nhgetch,
60     gnome_nh_poskey,
61     gnome_nhbell,
62     gnome_doprev_message,
63     gnome_yn_function,
64     gnome_getlin,
65     gnome_get_ext_cmd,
66     gnome_number_pad,
67     gnome_delay_output,
68 #ifdef CHANGE_COLOR	/* only a Mac option currently */
69     donull,
70     donull,
71 #endif
72     /* other defs that really should go away (they're tty specific) */
73     gnome_start_screen,
74     gnome_end_screen,
75     gnome_outrip,
76     genl_preference_update,
77 };
78 
79 /*
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
83                    not display them.
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
92 */
gnome_init_nhwindows(int * argc,char ** argv)93 void gnome_init_nhwindows(int* argc, char** argv)
94 {
95     /* Main window */
96     ghack_init_main_window( *argc, argv);
97     ghack_init_signals( );
98 
99 #ifdef HACKDIR
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");
103 #else
104 #   error HACKDIR is not defined!
105 #endif
106 
107     // gnome/gtk is not reentrant
108     set_option_mod_status("ignintr", DISP_IN_GAME);
109     flags.ignintr = TRUE;
110 
111     iflags.window_inited = TRUE;
112 
113     /* gnome-specific window creation */
114     WIN_WORN = gnome_create_nhwindow(NHW_WORN);
115 }
116 
117 
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].
121 */
122 void
gnome_player_selection()123 gnome_player_selection()
124 {
125     int n, i, sel;
126     const char** choices;
127     int* pickmap;
128 
129     /* prevent an unnecessary prompt */
130     rigid_role_checks();
131 
132     if (!flags.randomall && flags.initrole < 0) {
133 
134 	/* select a role */
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));
138 	for (;;) {
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;
144 		    else
145 			choices[n] = roles[i].name.m;
146 		    pickmap[n++] = i;
147 		}
148 	    }
149 	    if (n > 0) break;
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");
154 	}
155 	choices[n] = (const char *) 0;
156 	if (n > 1)
157 	    sel = ghack_player_sel_dialog(choices,
158 		_("Player selection"), _("Choose one of the following roles:"));
159 	else sel = 0;
160 	if (sel >= 0) sel = pickmap[sel];
161 	else if (sel == ROLE_NONE) {		/* Quit */
162 	    clearlocks();
163 	    gnome_exit_nhwindows(0);
164 	}
165 	free(choices);
166 	free(pickmap);
167     } else if (flags.initrole < 0) sel = ROLE_RANDOM;
168     else sel = flags.initrole;
169 
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();
174     }
175 
176     flags.initrole = sel;
177 
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);
186 	} else {
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))
191 		    n++;
192 	    }
193 	    if (n == 0) {
194 		for (i = 0; races[i].noun; i++) {
195 		    if (validrace(flags.initrole, i)) n++;
196 		}
197 	    }
198 
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,
203 			    flags.initalign)) {
204 		    choices[n] = races[i].noun;
205 		    pickmap[n++] = i;
206 		}
207 	    }
208 	    choices[n] = (const char *) 0;
209 	    /* Permit the user to pick, if there is more than one */
210 	    if (n > 1)
211 		sel = ghack_player_sel_dialog(choices, _("Race selection"),
212 			_("Choose one of the following races:"));
213 	    else sel = 0;
214 	    if (sel >= 0) sel = pickmap[sel];
215 	    else if (sel == ROLE_NONE) { /* Quit */
216 		clearlocks();
217 		gnome_exit_nhwindows(0);
218 	    }
219 	    flags.initrace = sel;
220 	    free(choices);
221 	    free(pickmap);
222 	}
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;
228 	}
229     }
230 
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);
241 	} else {
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))
246 		    n++;
247 	    }
248 	    if (n == 0) {
249 		for (i = 0; i < ROLE_GENDERS; i++) {
250 		    if (validgend(flags.initrole, flags.initrace, i)) n++;
251 		}
252 	    }
253 
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,
258 				flags.initalign)) {
259 		    choices[n] = genders[i].adj;
260 		    pickmap[n++] = i;
261 		}
262 	    }
263 	    choices[n] = (const char *) 0;
264 	    /* Permit the user to pick, if there is more than one */
265 	    if (n > 1)
266 		sel = ghack_player_sel_dialog(choices, _("Gender selection"),
267 			_("Choose one of the following genders:"));
268 	    else sel = 0;
269 	    if (sel >= 0) sel = pickmap[sel];
270 	    else if (sel == ROLE_NONE) { /* Quit */
271 		clearlocks();
272 		gnome_exit_nhwindows(0);
273 	    }
274 	    flags.initgend = sel;
275 	    free(choices);
276 	    free(pickmap);
277 	}
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;
283 	}
284     }
285 
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);
295 	} else {
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))
300 		    n++;
301 	    }
302 	    if (n == 0) {
303 		for (i = 0; i < ROLE_ALIGNS; i++)
304 		    if (validalign(flags.initrole, flags.initrace, i)) n++;
305 	    }
306 
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;
313 		    pickmap[n++] = i;
314 		}
315 	    }
316 	    choices[n] = (const char *) 0;
317 	    /* Permit the user to pick, if there is more than one */
318 	    if (n > 1)
319 		sel = ghack_player_sel_dialog(choices, _("Alignment selection"),
320 			_("Choose one of the following alignments:"));
321 	    else sel = 0;
322 	    if (sel >= 0) sel = pickmap[sel];
323 	    else if (sel == ROLE_NONE) { /* Quit */
324 		clearlocks();
325 		gnome_exit_nhwindows(0);
326 	    }
327 	    flags.initalign = sel;
328 	    free(choices);
329 	    free(pickmap);
330 	}
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;
336 	}
337     }
338 }
339 
340 
341 /* Ask the user for a player name. */
gnome_askname()342 void gnome_askname()
343 {
344     int ret;
345 
346     g_message("Asking name....");
347 
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);
351 
352     /* Quit if they want to quit... */
353     if (ret==-1)
354       {
355         gnome_exit_nhwindows(0);
356       }
357 }
358 
359 
360 /* Does window event processing (e.g. exposure events).
361    A noop for the tty and X window-ports.
362 */
gnome_get_nh_event()363 void gnome_get_nh_event()
364 {
365 	/* We handle our own events. */
366 	return;
367 }
368 
369 /* Exits the window system.  This should dismiss all windows,
370    except the "window" used for raw_print().  str is printed if possible.
371 */
gnome_exit_nhwindows(const char * str)372 void gnome_exit_nhwindows(const char *str)
373 {
374 	gtk_exit (0);
375 	terminate(EXIT_SUCCESS);
376 }
377 
378 /* Prepare the window to be suspended. */
gnome_suspend_nhwindows(const char * str)379 void gnome_suspend_nhwindows(const char *str)
380 {
381 	/* I don't think we need to do anything here... */
382 	return;
383 }
384 
385 
386 /* Restore the windows after being suspended. */
gnome_resume_nhwindows()387 void gnome_resume_nhwindows()
388 {
389 	/* Do Nothing.  Un-necessary since the GUI will refresh itself. */
390 	return;
391 }
392 
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)
399 */
400 winid
gnome_create_nhwindow(int type)401 gnome_create_nhwindow(int type)
402 {
403 
404   winid i = 0;
405 
406 /* Return the next available winid
407  */
408 
409   for (i=0; i<MAXWINDOWS; i++)
410       if (gnome_windowlist[i].win == NULL)
411           break;
412   if (i == MAXWINDOWS)
413       g_error ("ERROR:  No windows available...\n");
414   gnome_create_nhwindow_by_id( type, i);
415   return i;
416 }
417 
418 void
gnome_create_nhwindow_by_id(int type,winid i)419 gnome_create_nhwindow_by_id( int type, winid i)
420 {
421     switch (type)
422       {
423       case NHW_MAP:
424 	{
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);
428 	  break;
429 	}
430       case NHW_MESSAGE:
431 	{
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);
435 	  break;
436 	}
437       case NHW_STATUS:
438 	{
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);
442 	  break;
443 	}
444       case NHW_WORN:
445 	{
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);
449 	  break;
450 	}
451       case NHW_MENU:
452 	{
453 	  gnome_windowlist[i].type = NHW_MENU;
454 	  gnome_windowlist[i].win = ghack_init_menu_window( );
455 	  break;
456 	}
457       case NHW_TEXT:
458 	{
459 	  gnome_windowlist[i].win = ghack_init_text_window( );
460 	  gnome_windowlist[i].type = NHW_TEXT;
461 	  break;
462 	}
463       }
464 }
465 
466 /* This widget is being destroyed before its time--
467  * clear its entry from the windowlist.
468 */
gnome_delete_nhwindow_by_reference(GtkWidget * menuWin)469 void gnome_delete_nhwindow_by_reference( GtkWidget *menuWin)
470 {
471   int i;
472 
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;
477       break;
478     }
479   }
480 }
481 
482 /* Clear the given window, when asked to. */
gnome_clear_nhwindow(winid wid)483 void gnome_clear_nhwindow(winid wid)
484 {
485   if (gnome_windowlist[wid].win != NULL)
486     {
487       gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win),
488 		       ghack_signals[GHSIG_CLEAR]);
489     }
490 }
491 
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.
500 */
gnome_display_nhwindow(winid wid,BOOLEAN_P block)501 void gnome_display_nhwindow(winid wid, BOOLEAN_P block)
502 {
503   if (gnome_windowlist[wid].win != NULL)
504     {
505       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
506 		       ghack_signals[GHSIG_DISPLAY],
507 		       block);
508       if (block && (gnome_windowlist[wid].type == NHW_MAP))
509 	(void) gnome_nhgetch();
510     }
511 }
512 
513 
514 /* Destroy will dismiss the window if the window has not
515  * already been dismissed.
516 */
gnome_destroy_nhwindow(winid wid)517 void gnome_destroy_nhwindow(winid wid)
518 {
519     if ((wid == WIN_MAP) ||
520         (wid == WIN_MESSAGE) ||
521         (wid == WIN_STATUS)) {
522 	/* no thanks, I'll do these myself */
523 	return;
524     }
525     if (wid != -1 && gnome_windowlist[wid].win != NULL)
526       {
527 	gtk_widget_destroy(gnome_windowlist[wid].win);
528 	gnome_windowlist[wid].win = NULL;
529 	gnome_windowlist[wid].type = 0;
530       }
531 }
532 
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
536  the size of window.
537 */
gnome_curs(winid wid,int x,int y)538 void gnome_curs(winid wid, int x, int y)
539 {
540   if (wid != -1 && gnome_windowlist[wid].win != NULL)
541     {
542       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
543 		       ghack_signals[GHSIG_CURS], x, y);
544     }
545 }
546 
547 /*
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.
552 Attributes
553                    can be one of
554                         ATR_NONE (or 0)
555                         ATR_ULINE
556                         ATR_BOLD
557                         ATR_BLINK
558                         ATR_INVERSE
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
564                    to end-of-line.
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.
569 */
gnome_putstr(winid wid,int attr,const char * text)570 void gnome_putstr(winid wid, int attr, const char *text)
571 {
572     if ((wid >= 0) &&
573         (wid < MAXWINDOWS) &&
574         (gnome_windowlist[wid].win != NULL))
575     {
576       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
577 		       ghack_signals[GHSIG_PUTSTR],
578 		       (guint) attr,
579 		       text);
580     }
581 }
582 
583 /* Display the file named str.  Complain about missing files
584                    iff complain is TRUE.
585 */
gnome_display_file(const char * filename,BOOLEAN_P must_exist)586 void gnome_display_file(const char *filename,BOOLEAN_P must_exist)
587 {
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
591 	 * ones each time */
592 
593 	dlb *f;
594 
595         f = dlb_fopen(filename, "r");
596         if (!f) {
597 	  if (must_exist) {
598 	    GtkWidget *box;
599             char message[90];
600             sprintf(message, "Warning! Could not find file: %s\n",filename);
601 
602 	    box = gnome_message_box_new (_(message),
603 		    GNOME_MESSAGE_BOX_ERROR,
604 		    GNOME_STOCK_BUTTON_OK,
605 		    NULL);
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);
611 	  }
612         }
613 	else {
614     	  GtkWidget *txtwin, *gless, *frametxt;
615 #define LLEN 128
616 	  char line[LLEN], *textlines;
617 	  int num_lines, charcount;
618 
619 	  txtwin = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK,
620 				    NULL);
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);
628 
629 	  /*
630 	   * Count the number of lines and characters in the file.
631 	   */
632 	  num_lines = 0;
633 	  charcount = 1;
634 	  while (dlb_fgets(line, LLEN, f)) {
635 	    num_lines++;
636 	    charcount += strlen(line);
637 	  }
638 	  (void) dlb_fclose(f);
639 
640 	  /* Ignore empty files */
641 	  if (num_lines == 0) return;
642 
643 	  /*
644 	   * Re-open the file and read the data into a buffer.
645 	   */
646 	  textlines = (char *) alloc((unsigned int) charcount);
647 	  textlines[0] = '\0';
648 	  f = dlb_fopen( filename, RDTMODE);
649 
650 	  while (dlb_fgets(line, LLEN, f)) {
651 	    (void) strcat(textlines, line);
652 	  }
653 	  (void) dlb_fclose(f);
654 
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,
659                              TRUE, TRUE, 0);
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));
665 	  free(textlines);
666         }
667 }
668 
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
672    be used for menus.
673 */
gnome_start_menu(winid wid)674 void gnome_start_menu(winid wid)
675 {
676   if (wid != -1)
677     {
678       if (gnome_windowlist[wid].win == NULL && gnome_windowlist[wid].type != 0)
679 	{
680 	  gnome_create_nhwindow_by_id(gnome_windowlist[wid].type, wid);
681 	}
682         gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
683 		       ghack_signals[GHSIG_START_MENU]);
684     }
685 }
686 
687 /*
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.
717 */
gnome_add_menu(winid wid,int glyph,const ANY_P * identifier,CHAR_P accelerator,CHAR_P group_accel,int attr,const char * str,BOOLEAN_P presel)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)
721 {
722   GHackMenuItem item;
723   item.glyph =  glyph;
724   item.identifier = identifier;
725   item.accelerator = accelerator;
726   item.group_accel = group_accel;
727   item.attr = attr;
728   item.str = str;
729   item.presel = presel;
730 
731   if (wid != -1 && gnome_windowlist[wid].win != NULL)
732     {
733       gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
734 		       ghack_signals[GHSIG_ADD_MENU],
735 		       &item);
736     }
737 }
738 
739 /*
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
744                    be printed.
745                 ** This probably shouldn't flush the window any more (if
746                 ** it ever did).  That should be select_menu's job.  -dean
747 */
gnome_end_menu(winid wid,const char * prompt)748 void gnome_end_menu(winid wid, const char *prompt)
749 {
750     if (wid != -1 && gnome_windowlist[wid].win != NULL)
751       {
752 	gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
753 			 ghack_signals[GHSIG_END_MENU],
754 			 prompt);
755       }
756 }
757 
758 /*
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.
782 */
gnome_select_menu(winid wid,int how,MENU_ITEM_P ** selected)783 int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected)
784 {
785     int nReturned = -1;
786 
787     if (wid != -1 && gnome_windowlist[wid].win != NULL &&
788         gnome_windowlist[wid].type == NHW_MENU)
789       {
790 	nReturned=ghack_menu_window_select_menu (gnome_windowlist[wid].win,
791 				       selected, how);
792       }
793 
794     return nReturned;
795 }
796 
797 /*
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.
801 */
gnome_update_inventory()802 void gnome_update_inventory()
803 {
804     ghack_main_window_update_inventory();
805 }
806 
807 /*
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
810                    for the moment
811 */
gnome_mark_synch()812 void gnome_mark_synch()
813 {
814 	/* Do nothing */
815 }
816 
817 /*
818 wait_synch()    -- Wait until all pending output is complete (*flush*() for
819                    streams goes here).
820                 -- May also deal with exposure events etc. so that the
821                    display is OK when return from wait_synch().
822 */
gnome_wait_synch()823 void gnome_wait_synch()
824 {
825 	/* Do nothing */
826 }
827 
828 /*
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.
832 */
gnome_cliparound(int x,int y)833 void gnome_cliparound(int x, int y)
834 {
835   /* FIXME!!!  winid should be a parameter!!!
836    * Call a function that Does The Right Thing(tm).
837   */
838     gnome_cliparound_proper(WIN_MAP,x,y);
839 }
840 
gnome_cliparound_proper(winid wid,int x,int y)841 void gnome_cliparound_proper(winid wid, int x, int y)
842 {
843     if (wid != -1 && gnome_windowlist[wid].win != NULL)
844       {
845 	gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win),
846 			 ghack_signals[GHSIG_CLIPAROUND],
847 			 (guint) x,
848 			 (guint) y);
849       }
850 }
851 
852 /*
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).
858 */
gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)859 void gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph)
860 {
861     if (wid != -1 && gnome_windowlist[wid].win != NULL)
862       {
863 	GdkImlibImage *im;
864 
865 	im = ghack_image_from_glyph( glyph, FALSE);
866 
867 	gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win),
868 			 ghack_signals[GHSIG_PRINT_GLYPH],
869 			 (guint) x,
870 			 (guint) y,
871 			 im,
872 			 NULL);
873     }
874 }
875 
876 /*
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").
884 */
gnome_raw_print(const char * str)885 void gnome_raw_print(const char *str)
886 {
887     tty_raw_print(str);
888 }
889 
890 /*
891 raw_print_bold(str)
892                 -- Like raw_print(), but prints in bold/standout (if
893 possible).
894 */
gnome_raw_print_bold(const char * str)895 void gnome_raw_print_bold(const char *str)
896 {
897     tty_raw_print_bold(str);
898 }
899 
900 /*
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.
905 */
gnome_nhgetch()906 int gnome_nhgetch()
907 {
908     int key;
909     GList *theFirst;
910     gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win),
911 		       ghack_signals[GHSIG_FADE_HIGHLIGHT]);
912 
913     g_askingQuestion = 1;
914     /* Process events until a key press event arrives. */
915     while ( g_numKeys == 0 )
916 	gtk_main_iteration();
917 
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);
922     g_numKeys--;
923     g_askingQuestion = 0;
924     return ( key);
925 }
926 
927 /*
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.
933                    mod may be one of
934 
935                         CLICK_1         -- mouse click type 1
936                         CLICK_2         -- mouse click type 2
937 
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.
941 */
gnome_nh_poskey(int * x,int * y,int * mod)942 int gnome_nh_poskey(int *x, int *y, int *mod)
943 {
944     gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win),
945 		       ghack_signals[GHSIG_FADE_HIGHLIGHT]);
946 
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();
951 
952     if (g_numKeys > 0) {
953 	int key;
954 	GList *theFirst;
955 
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);
960 	g_numKeys--;
961 	return ( key);
962     }
963     else {
964 	GHClick *click;
965 	GList *theFirst;
966 
967 	theFirst = g_list_first( g_clickBuffer);
968 	g_clickBuffer = g_list_remove_link(g_clickBuffer, theFirst);
969 	click = (GHClick*) theFirst->data;
970 	*x=click->x;
971         *y=click->y;
972         *mod=click->mod;
973 	g_free( click);
974 	g_list_free_1( theFirst);
975 	g_numClicks--;
976 	return ( 0);
977     }
978 }
979 
980 /*
981 nhbell()        -- Beep at user.  [This will exist at least until sounds are
982                    redone, since sounds aren't attributable to windows anyway.]
983 */
gnome_nhbell()984 void gnome_nhbell()
985 {
986     /* FIXME!!! Play a cool GNOME sound instead */
987     gdk_beep();
988 }
989 
990 /*
991 doprev_message()
992                 -- Display previous messages.  Used by the ^P command.
993                 -- On the tty-port this scrolls WIN_MESSAGE back one line.
994 */
gnome_doprev_message()995 int gnome_doprev_message()
996 {
997     /* Do Nothing.  They can read old messages using the scrollbar. */
998     return 0;
999 }
1000 
1001 /*
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.
1019 */
gnome_yn_function(const char * question,const char * choices,CHAR_P def)1020 char gnome_yn_function(const char *question, const char *choices,
1021 		CHAR_P def)
1022 {
1023     int ch;
1024     int result=-1;
1025     char message[BUFSZ];
1026     char yn_esc_map='\033';
1027     GtkWidget *mainWnd = ghack_get_main_window();
1028 
1029 
1030     if (choices) {
1031 	char *cb, choicebuf[QBUFSZ];
1032 	Strcpy(choicebuf, choices);
1033 	if ((cb = index(choicebuf, '\033')) != 0) {
1034 	    /* anything beyond <esc> is hidden */
1035 	    *cb = '\0';
1036 	}
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));
1042     } else {
1043 	Strcpy(message, question);
1044     }
1045 
1046 
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));
1050     }
1051 
1052     /* Only here if main window is not present */
1053     while (result<0) {
1054 	ch=gnome_nhgetch();
1055 	if (ch=='\033') {
1056 	    result=yn_esc_map;
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)) {
1060 		result=def;
1061 	    } else {
1062 		gnome_nhbell();
1063 		/* and try again... */
1064 	    }
1065 	} else {
1066 	    result=ch;
1067 	}
1068     }
1069     return result;
1070 }
1071 
1072 /*
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.
1081 */
gnome_getlin(const char * question,char * input)1082 void gnome_getlin(const char *question, char *input)
1083 {
1084     int ret;
1085 
1086     ret = ghack_ask_string_dialog(question, "", "nethack", input);
1087 
1088     if (ret == -1)
1089 	input[0] = 0;
1090 }
1091 
1092 /*
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.
1097 */
gnome_get_ext_cmd()1098 int gnome_get_ext_cmd()
1099 {
1100     return ghack_menu_ext_cmd();
1101 }
1102 
1103 
1104 /*
1105 number_pad(state)
1106 	    -- Initialize the number pad to the given state.
1107 */
gnome_number_pad(int state)1108 void gnome_number_pad(int state)
1109 {
1110     /* Do Nothing */
1111 }
1112 
1113 /*
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.
1117 */
gnome_delay_output()1118 void gnome_delay_output()
1119 {
1120     if (gnome_windowlist[WIN_MESSAGE].win != NULL) {
1121 	gtk_signal_emit( GTK_OBJECT (gnome_windowlist[WIN_MESSAGE].win),
1122 	ghack_signals[GHSIG_DELAY],
1123 	(guint) 50);
1124     }
1125 }
1126 
1127 /*
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.
1133 */
gnome_start_screen()1134 void gnome_start_screen()
1135 {
1136     /* Do Nothing */
1137 }
1138 
1139 /*
1140 end_screen()    -- Only used on Unix tty ports, but must be declared for
1141 	       completeness.  The complement of start_screen().
1142 */
gnome_end_screen()1143 void gnome_end_screen()
1144 {
1145     /* Do Nothing */
1146 }
1147 
1148 /*
1149 outrip(winid, int)
1150 	    -- The tombstone code.  If you want the traditional code use
1151 	       genl_outrip for the value and check the #if in rip.c.
1152 */
gnome_outrip(winid wid,int how)1153 void gnome_outrip(winid wid, int how)
1154 {
1155     /* Follows roughly the same algorithm as genl_outrip() */
1156     char buf[BUFSZ];
1157     char ripString[BUFSZ]="\0";
1158     extern const char *killed_by_prefix[];
1159 
1160     /* Put name on stone */
1161     Sprintf(buf, "%s\n", plname);
1162     Strcat(ripString, buf);
1163 
1164     /* Put $ on stone */
1165     Sprintf(buf, "%ld Au\n",
1166 #ifndef GOLDOBJ
1167 		u.ugold);
1168 #else
1169 		done_money);
1170 #endif
1171     Strcat(ripString, buf);
1172 
1173     /* Put together death description */
1174     switch (killer_format) {
1175 	    default: impossible("bad killer format?");
1176 	    case KILLED_BY_AN:
1177 		    Strcpy(buf, killed_by_prefix[how]);
1178 		    Strcat(buf, an(killer));
1179 		    break;
1180 	    case KILLED_BY:
1181 		    Strcpy(buf, killed_by_prefix[how]);
1182 		    Strcat(buf, killer);
1183 		    break;
1184 	    case NO_KILLER_PREFIX:
1185 		    Strcpy(buf, killer);
1186 		    break;
1187     }
1188     /* Put death type on stone */
1189     Strcat(ripString, buf);
1190     Strcat(ripString, "\n");
1191 
1192     /* Put year on stone */
1193     Sprintf(buf, "%4d\n", getyear());
1194     Strcat(ripString, buf);
1195 
1196     ghack_text_window_rip_string( ripString);
1197 }
1198