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