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