1 /*	SCCS Id: @(#)gnmain.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 #include "gnmain.h"
6 #include "gnsignal.h"
7 #include "gnbind.h"
8 #include "gnopts.h"
9 #include <gnome.h>
10 #include <getopt.h>
11 #include <gdk/gdk.h>
12 #include <sys/time.h>
13 #include <unistd.h>
14 #include <signal.h>
15 #include "hack.h"
16 #include "date.h"
17 
18 static GtkWidget* mainWindow=NULL;
19 static GtkWidget *about=NULL;
20 static GtkWidget* hBoxFirstRow;
21 static GtkWidget* vBoxMain;
22 
23 int restarted = 0;
24 int os_x = 0, os_y = 0, os_w = 0, os_h = 0;
25 
26 
27 static GnomeClient *session_id;
28 
29 static
ghack_quit_game(GtkWidget * widget,int button)30 void ghack_quit_game(GtkWidget *widget, int button)
31 {
32     gtk_widget_hide(widget);
33     if (button == 0) {
34 	gnome_exit_nhwindows(0);
35 	gtk_object_unref(GTK_OBJECT(session_id));
36     }
37 }
38 
39 static
ghack_quit_game_cb(GtkWidget * widget,gpointer data)40 void ghack_quit_game_cb(GtkWidget *widget, gpointer data)
41 {
42     GtkWidget *box;
43     box = gnome_message_box_new(_("Do you really want to quit?"),
44 	    GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES,
45 	    GNOME_STOCK_BUTTON_NO, NULL);
46     gnome_dialog_set_default( GNOME_DIALOG(box), 1);
47     gnome_dialog_set_parent (GNOME_DIALOG (box),
48 	    GTK_WINDOW (ghack_get_main_window ()) );
49     gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0);
50     gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0);
51 
52     gtk_window_set_modal( GTK_WINDOW(box), TRUE);
53     gtk_signal_connect( GTK_OBJECT(box), "clicked",
54 	    (GtkSignalFunc)ghack_quit_game, NULL);
55     gtk_widget_show(box);
56 }
57 
58 static
ghack_save_game(GtkWidget * widget,int button)59 void ghack_save_game(GtkWidget *widget, int button)
60 {
61     gtk_widget_hide(widget);
62     if (button == 0) {
63 	if(dosave0()) {
64 	    /* make sure they see the Saving message */
65 	    display_nhwindow(WIN_MESSAGE, TRUE);
66 	    gnome_exit_nhwindows("Be seeing you...");
67 	} else (void)doredraw();
68     }
69 }
70 
ghack_save_game_cb(GtkWidget * widget,gpointer data)71 void ghack_save_game_cb(GtkWidget *widget, gpointer data)
72 {
73     GtkWidget *box;
74     box = gnome_message_box_new(_("Quit and save the current game?"),
75 	    GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES,
76 	    GNOME_STOCK_BUTTON_NO, NULL);
77     gnome_dialog_set_default( GNOME_DIALOG(box), 1);
78     gnome_dialog_set_parent (GNOME_DIALOG (box),
79 	    GTK_WINDOW (ghack_get_main_window ()) );
80     gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0);
81     gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0);
82 
83     gtk_window_set_modal( GTK_WINDOW(box), TRUE);
84     gtk_signal_connect( GTK_OBJECT(box), "clicked",
85 	    (GtkSignalFunc)ghack_save_game, NULL);
86     gtk_widget_show(box);
87 }
88 
89 static
ghack_new_game(GtkWidget * widget,int button)90 void ghack_new_game(GtkWidget *widget, int button)
91 {
92     if (button == 0) {
93 	g_message("This feature is not yet implemented.  Sorry.");
94     }
95 }
96 
97 static
ghack_new_game_cb(GtkWidget * widget,gpointer data)98 void ghack_new_game_cb(GtkWidget *widget, gpointer data)
99 {
100     GtkWidget *box;
101     box = gnome_message_box_new(_("Start a new game?"),
102 	    GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES,
103 	    GNOME_STOCK_BUTTON_NO, NULL);
104     gnome_dialog_set_default( GNOME_DIALOG(box), 1);
105     gnome_dialog_set_parent (GNOME_DIALOG (box),
106 	    GTK_WINDOW (ghack_get_main_window ()) );
107     gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0);
108     gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0);
109 
110     gtk_window_set_modal( GTK_WINDOW(box), TRUE);
111     gtk_signal_connect( GTK_OBJECT(box), "clicked",
112 	    (GtkSignalFunc)ghack_new_game, NULL);
113     gtk_widget_show(box);
114 }
115 
116 static void
about_destroy_callback(void)117 about_destroy_callback (void)
118 {
119     about = NULL;
120 }
121 
122 static void
ghack_about_cb(GtkWidget * widget,gpointer data)123 ghack_about_cb(GtkWidget *widget, gpointer data)
124 {
125     char buf[BUFSZ]="\0";
126     char buf1[BUFSZ]="\0";
127     const gchar *authors[] = {"Erik Andersen", "Anthony Taylor",
128 	"Jeff Garzik", "The Nethack Dev Team", NULL};
129 
130     if (about) {
131 	gdk_window_raise (about->window);
132 	return;
133     }
134 
135     getversionstring(buf);
136     strcat( buf1, VERSION_STRING);
137     strcat( buf,
138       _("\nSend comments and bug reports to: nethack-bugs@nethack.org\n"
139       "This game is free software. See License for details."));
140     about = gnome_about_new(_("Nethack"),
141 	    buf1, "Copyright (C) 1985-2002 Mike Stephenson",
142 	    (const char **)authors, buf,
143 	    NULL);
144 
145     gtk_signal_connect (GTK_OBJECT (about), "destroy",
146 	(GtkSignalFunc) about_destroy_callback, NULL);
147 
148     gtk_widget_show(about);
149 }
150 
151 static void
ghack_settings_cb(GtkWidget * widget,gpointer data)152 ghack_settings_cb(GtkWidget *widget, gpointer data)
153 {
154     ghack_settings_dialog();
155 }
156 
157 static void
ghack_accelerator_selected(GtkWidget * widget,gpointer data)158 ghack_accelerator_selected (GtkWidget *widget, gpointer data)
159 {
160     GdkEventKey event;
161     int key = GPOINTER_TO_INT( data);
162     /* g_message("An accelerator for \"%c\" was selected", key); */
163     /* stuff a key directly into the keybuffer */
164     event.state=0;
165     event.keyval=key;
166     ghack_handle_key_press(NULL, &event, NULL);
167 }
168 
169 #ifndef M
170 # ifndef NHSTDC
171 #  define M(c)          (0x80 | (c))
172 # else
173 #  define M(c)          ((c) - 128)
174 # endif /* NHSTDC */
175 #endif
176 #ifndef C
177 #define C(c)            (0x1f & (c))
178 #endif
179 
180 
181 GnomeUIInfo game_tree[] =
182 {
183     {
184 	GNOME_APP_UI_ITEM, N_ ("_Change Settings..."),
185 	N_("Change Game Settings"), ghack_settings_cb, NULL, NULL,
186 	GNOME_APP_PIXMAP_NONE, NULL, 0,0, NULL
187     },
188     GNOMEUIINFO_SEPARATOR,
189     {
190 	GNOME_APP_UI_ITEM, N_("Version"), NULL,
191 	ghack_accelerator_selected, GINT_TO_POINTER('v'), NULL,
192 	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'v',0
193     },
194     {
195 	GNOME_APP_UI_ITEM, N_("History..."), NULL,
196 	ghack_accelerator_selected, GINT_TO_POINTER('V'), NULL,
197 	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'V',GDK_SHIFT_MASK
198     },
199     {
200 	GNOME_APP_UI_ITEM, N_("Compilation..."), NULL,
201 	ghack_accelerator_selected, GINT_TO_POINTER(M('v')), NULL,
202 	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT,'v',GDK_MOD1_MASK
203     },
204     {
205 	GNOME_APP_UI_ITEM, N_("Options..."), NULL,
206 	ghack_accelerator_selected, GINT_TO_POINTER('O'), NULL,
207 	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF, 'O', GDK_SHIFT_MASK
208     },
209     {
210 	GNOME_APP_UI_ITEM, N_("Explore Mode..."), NULL,
211 	ghack_accelerator_selected, GINT_TO_POINTER('X'), NULL,
212 	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'X', GDK_SHIFT_MASK
213     },
214     GNOMEUIINFO_SEPARATOR,
215     GNOMEUIINFO_MENU_NEW_GAME_ITEM(ghack_new_game_cb, NULL),
216     GNOMEUIINFO_MENU_SAVE_ITEM(ghack_save_game_cb, NULL),
217     {
218 	GNOME_APP_UI_ITEM, N_("Exit"), NULL,
219 	ghack_quit_game_cb, GINT_TO_POINTER(M('Q')), NULL,
220 	GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'Q', GDK_MOD1_MASK
221     },
222     GNOMEUIINFO_END
223 };
224 
225 
226 
227 GnomeUIInfo edit_menu[] = {
228 	   {
229 	       GNOME_APP_UI_ITEM, N_("Inventory"),
230 	       N_("Edit/View your Inventory"), ghack_accelerator_selected,
231 	       GINT_TO_POINTER('i'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i', 0
232 	   },
233 	   {
234 	       GNOME_APP_UI_ITEM, N_("Discoveries"),
235 	       N_("Edit/View your Discoveries"),
236 	       ghack_accelerator_selected,
237 	       GINT_TO_POINTER('\\'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '\\',0
238 	   },
239 	   {
240 	       GNOME_APP_UI_ITEM, N_("List/reorder your spells"),
241 	       N_("List/reorder your spells"), ghack_accelerator_selected,
242 	       GINT_TO_POINTER('x'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'x', 0
243 	   },
244 	   {
245 	       GNOME_APP_UI_ITEM, N_("Adjust letters"),
246 	       N_("Adjust letter for items in your Inventory"), ghack_accelerator_selected,
247 	        GINT_TO_POINTER(M('a')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a', GDK_MOD1_MASK
248 	   },
249 	   GNOMEUIINFO_SEPARATOR,
250 	   {
251 	       GNOME_APP_UI_ITEM, N_("Name object"),
252 	       N_("Assign a name to an object"), ghack_accelerator_selected,
253 	       GINT_TO_POINTER(M('n')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'n', GDK_MOD1_MASK
254 	   },
255 	   {
256 	       GNOME_APP_UI_ITEM, N_("Name creature"),
257 	       N_("Assign a name to a creature"), ghack_accelerator_selected,
258 	       GINT_TO_POINTER('C'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'C', GDK_SHIFT_MASK
259 	   },
260 	   GNOMEUIINFO_SEPARATOR,
261 	   {
262 	       GNOME_APP_UI_ITEM, N_("Qualifications"),
263 	       N_("Edit your Qualifications"), ghack_accelerator_selected,
264 	       GINT_TO_POINTER(M('e')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e',GDK_MOD1_MASK
265 	   },
266            GNOMEUIINFO_END
267 };
268 
269 
270 GnomeUIInfo apparel_menu[] = {
271 	   {
272 	       GNOME_APP_UI_ITEM, N_("Wield Weapon"),
273 	       N_("Select a weapon to fight with"),
274 	       ghack_accelerator_selected,
275 	       GINT_TO_POINTER('w'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w',0
276 	   },
277 	   {
278 	       GNOME_APP_UI_ITEM, N_("Remove Apparel..."),
279 	       N_("Remove apparel dialog bog"), ghack_accelerator_selected,
280 	       GINT_TO_POINTER('A'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'A',GDK_SHIFT_MASK
281 	   },
282 	   GNOMEUIINFO_SEPARATOR,
283 	   {
284 	       GNOME_APP_UI_ITEM, N_("Wear Armor"),
285 	       N_("Put on armor"), ghack_accelerator_selected,
286 	       GINT_TO_POINTER('W'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'W',GDK_SHIFT_MASK
287 	   },
288 	   {
289 	       GNOME_APP_UI_ITEM, N_("Take off Armor"),
290 	       N_("Take off armor you are wearing"), ghack_accelerator_selected,
291 	       GINT_TO_POINTER('T'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'T',GDK_SHIFT_MASK
292 	   },
293 	   GNOMEUIINFO_SEPARATOR,
294 	   {
295 	       GNOME_APP_UI_ITEM, N_("Put on non-armor"),
296 	       N_("Put on non-armor apparel"), ghack_accelerator_selected,
297 	       GINT_TO_POINTER('P'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'P',GDK_SHIFT_MASK
298 	   },
299 	   {
300 	       GNOME_APP_UI_ITEM, N_("Remove non-armor"),
301 	       N_("Remove non-armor apparel you are wearing"), ghack_accelerator_selected,
302 	       GINT_TO_POINTER('R'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R',GDK_SHIFT_MASK
303 	   },
304            GNOMEUIINFO_END
305 };
306 
307 GnomeUIInfo action_menu[] = {
308 	   {
309 	       GNOME_APP_UI_ITEM, N_("Get"),
310 	       N_("Pick up things at the current location"),
311 	       ghack_accelerator_selected,
312 	       GINT_TO_POINTER(','), NULL, GNOME_APP_PIXMAP_NONE, NULL, ',',0
313 	   },
314 	   {
315 	       GNOME_APP_UI_ITEM, N_("Loot"),
316 	       N_("loot a box on the floor"),
317 	       ghack_accelerator_selected,
318 	       GINT_TO_POINTER(M('l')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'l',GDK_MOD1_MASK
319 	   },
320 	   {
321 	       GNOME_APP_UI_ITEM, N_("Sit"),
322 	       N_("sit down"),
323 	       ghack_accelerator_selected,
324 	       GINT_TO_POINTER(M('s')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's',GDK_MOD1_MASK
325 	   },
326 	   {
327 	       GNOME_APP_UI_ITEM, N_("Force"),
328 	       N_("force a lock"),
329 	       ghack_accelerator_selected,
330 	       GINT_TO_POINTER(M('f')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'f',GDK_MOD1_MASK
331 	   },
332 	   {
333 	       GNOME_APP_UI_ITEM, N_("Kick"),
334 	       N_("kick something (usually a door)"),
335 	       ghack_accelerator_selected,
336 	       GINT_TO_POINTER(C('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',GDK_CONTROL_MASK
337 	   },
338 	   {
339 	       GNOME_APP_UI_ITEM, N_("Jump"),
340 	       N_("jump to another location"),
341 	       ghack_accelerator_selected,
342 	       GINT_TO_POINTER(M('j')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'j',GDK_MOD1_MASK
343 	   },
344 #ifdef STEED
345 	   {
346 	       GNOME_APP_UI_ITEM, N_("Ride"),
347 	       N_("Ride (or stop riding) a monster"),
348 	       doride,
349 	       GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R',GDK_MOD1_MASK
350 	   },
351 #endif
352 	   {
353 	       GNOME_APP_UI_ITEM, N_("Wipe face"),
354 	       N_("wipe off your face"),
355 	       ghack_accelerator_selected,
356 	       GINT_TO_POINTER(M('w')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w',GDK_MOD1_MASK
357 	   },
358 	   {
359 	       GNOME_APP_UI_ITEM, N_("Throw/Shoot"),
360 	       N_("throw or shoot a weapon"),
361 	       ghack_accelerator_selected,
362 	       GINT_TO_POINTER('t'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',0
363 	   },
364 	   {
365 	       GNOME_APP_UI_ITEM, N_("Quiver/Ready"),
366 	       N_("ready or quiver some ammunition"),
367 	       ghack_accelerator_selected,
368 	       GINT_TO_POINTER('Q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Q',GDK_SHIFT_MASK,
369 	   },
370 	   {
371 	       GNOME_APP_UI_ITEM, N_("Open Door"),
372 	       N_("open a door"),
373 	       ghack_accelerator_selected,
374 	       GINT_TO_POINTER('o'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o',0
375 	   },
376 	   {
377 	       GNOME_APP_UI_ITEM, N_("Close Door"),
378 	       N_("open a door"),
379 	       ghack_accelerator_selected,
380 	       GINT_TO_POINTER('c'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c',0
381 	   },
382 	   GNOMEUIINFO_SEPARATOR,
383 	   {
384 	       GNOME_APP_UI_ITEM, N_("Drop"),
385 	       N_("drop an object"),
386 	       ghack_accelerator_selected,
387 	       GINT_TO_POINTER('d'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',0
388 	   },
389 	   {
390 	       GNOME_APP_UI_ITEM, N_("Drop Many"),
391 	       N_("drop selected types of objects"),
392 	       ghack_accelerator_selected,
393 	       GINT_TO_POINTER('D'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'D',GDK_SHIFT_MASK
394 	   },
395 	   {
396 	       GNOME_APP_UI_ITEM, N_("Eat"),
397 	       N_("eat something"),
398 	       ghack_accelerator_selected,
399 	       GINT_TO_POINTER('e'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e',0
400 	   },
401 	   {
402 	       GNOME_APP_UI_ITEM, N_("Engrave"),
403 	       N_("write a message in the dust on the floor"),
404 	       ghack_accelerator_selected,
405 	       GINT_TO_POINTER('E'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'E',GDK_SHIFT_MASK
406 	   },
407 	   {
408 	       GNOME_APP_UI_ITEM, N_("Apply"),
409 	       N_("apply or use a tool (pick-axe, key, camera, etc.)"),
410 	       ghack_accelerator_selected,
411 	       GINT_TO_POINTER('a'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a',0
412 	   },
413 	   GNOMEUIINFO_SEPARATOR,
414 	   {
415 	       GNOME_APP_UI_ITEM, N_("Up"),
416 	       N_("go up the stairs"),
417 	       ghack_accelerator_selected,
418 	       GINT_TO_POINTER('<'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '<',0
419 	   },
420 	   {
421 	       GNOME_APP_UI_ITEM, N_("Down"),
422 	       N_("go down the stairs"),
423 	       ghack_accelerator_selected,
424 	       GINT_TO_POINTER('>'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '>',0
425 	   },
426 	   {
427 	       GNOME_APP_UI_ITEM, N_("Rest"),
428 	       N_("wait for a moment"),
429 	       ghack_accelerator_selected,
430 	       GINT_TO_POINTER('.'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '.',0
431 	   },
432 	   {
433 	       GNOME_APP_UI_ITEM, N_("Search"),
434 	       N_("search for secret doors, hidden traps and monsters"),
435 	       ghack_accelerator_selected,
436 	       GINT_TO_POINTER('s'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's',0
437 	   },
438 	   GNOMEUIINFO_SEPARATOR,
439 	   {
440 	       GNOME_APP_UI_ITEM, N_("Chat"),
441 	       N_("talk to someone"),
442 	       ghack_accelerator_selected,
443 	       GINT_TO_POINTER(M('c')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c',GDK_MOD1_MASK
444 	   },
445 	   {
446 	       GNOME_APP_UI_ITEM, N_("Pay"),
447 	       N_("pay your bill to the shopkeeper"),
448 	       ghack_accelerator_selected,
449 	       GINT_TO_POINTER('p'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p',0
450 	   },
451            GNOMEUIINFO_END
452 };
453 
454 GnomeUIInfo magic_menu[] = {
455 	   {
456 	       GNOME_APP_UI_ITEM, N_("Quaff potion"),
457 	       N_("drink a potion"),
458 	       ghack_accelerator_selected,
459 	       GINT_TO_POINTER('q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'q',0
460 	   },
461 	   {
462 	       GNOME_APP_UI_ITEM, N_("Read Book/Scroll"),
463 	       N_("read a spell book or a scroll"),
464 	       ghack_accelerator_selected,
465 	       GINT_TO_POINTER('r'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r',0
466 	   },
467 	   {
468 	       GNOME_APP_UI_ITEM, N_("Zap Wand"),
469 	       N_("zap a wand"),
470 	       ghack_accelerator_selected,
471 	       GINT_TO_POINTER('z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'z',0
472 	   },
473 	   {
474 	       GNOME_APP_UI_ITEM, N_("Zap Spell"),
475 	       N_("cast a spell"),
476 	       ghack_accelerator_selected,
477 	       GINT_TO_POINTER('Z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Z',GDK_SHIFT_MASK
478 	   },
479 	   GNOMEUIINFO_SEPARATOR,
480 	   {
481 	       GNOME_APP_UI_ITEM, N_("Dip"),
482 	       N_("dip an object into something"),
483 	       ghack_accelerator_selected,
484 	       GINT_TO_POINTER(M('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',GDK_MOD1_MASK
485 	   },
486 	   {
487 	       GNOME_APP_UI_ITEM, N_("Rub"),
488 	       N_("Rub something (i.e. a lamp)"),
489 	       ghack_accelerator_selected,
490 	       GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r',GDK_MOD1_MASK
491 	   },
492 	   {
493 	       GNOME_APP_UI_ITEM, N_("Invoke"),
494 	       N_("invoke an object's special powers"),
495 	       ghack_accelerator_selected,
496 	       GINT_TO_POINTER(M('i')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i',GDK_MOD1_MASK
497 	   },
498 	   GNOMEUIINFO_SEPARATOR,
499 	   {
500 	       GNOME_APP_UI_ITEM, N_("Offer"),
501 	       N_("offer a sacrifice to the gods"),
502 	       ghack_accelerator_selected,
503 	       GINT_TO_POINTER(M('o')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o',GDK_MOD1_MASK
504 	   },
505 	   {
506 	       GNOME_APP_UI_ITEM, N_("Pray"),
507 	       N_("pray to the gods for help"),
508 	       ghack_accelerator_selected,
509 	       GINT_TO_POINTER(M('p')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p',GDK_MOD1_MASK
510 	   },
511 	   GNOMEUIINFO_SEPARATOR,
512 	   {
513 	       GNOME_APP_UI_ITEM, N_("Teleport"),
514 	       N_("teleport (if you can)"),
515 	       ghack_accelerator_selected,
516 	       GINT_TO_POINTER(C('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',GDK_CONTROL_MASK
517 	   },
518 	   {
519 	       GNOME_APP_UI_ITEM, N_("Monster Action"),
520 	       N_("use a monster's special ability"),
521 	       ghack_accelerator_selected,
522 	       GINT_TO_POINTER(M('m')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'm',GDK_MOD1_MASK
523 	   },
524 	   {
525 	       GNOME_APP_UI_ITEM, N_("Turn Undead"),
526 	       N_("turn undead"),
527 	       ghack_accelerator_selected,
528 	       GINT_TO_POINTER(M('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',GDK_MOD1_MASK
529 	   },
530            GNOMEUIINFO_END
531 };
532 
533 GnomeUIInfo help_menu[] = {
534             {
535 		GNOME_APP_UI_ITEM, N_("About..."),
536 		N_("About GnomeHack"), ghack_about_cb, NULL, NULL,
537 		GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 0, 0, NULL
538 	    },
539 	   {
540 	       GNOME_APP_UI_ITEM, N_("Help"), NULL,
541 	       ghack_accelerator_selected,
542 	       GINT_TO_POINTER('?'), NULL, GNOME_APP_PIXMAP_STOCK,
543 	       GNOME_STOCK_MENU_ABOUT, '?', 0
544 	   },
545 	   GNOMEUIINFO_SEPARATOR,
546 	   {
547 	       GNOME_APP_UI_ITEM, N_("What is here"),
548 	       N_("Check what items occupy the current location"),
549 	       ghack_accelerator_selected,
550 	       GINT_TO_POINTER(':'), NULL, GNOME_APP_PIXMAP_STOCK,
551 	       GNOME_STOCK_MENU_ABOUT, ':',0
552 	   },
553 	   {
554 	       GNOME_APP_UI_ITEM, N_("What is that"),
555 	       N_("Identify an object"),
556 	       ghack_accelerator_selected,
557 	       GINT_TO_POINTER(';'), NULL, GNOME_APP_PIXMAP_STOCK,
558 	       GNOME_STOCK_MENU_ABOUT, ';',0
559 	   },
560 	   {
561 	       GNOME_APP_UI_ITEM, N_("Identify a map symbol"),
562 	       N_("Identify a map symbol"),
563 	       ghack_accelerator_selected,
564 	       GINT_TO_POINTER('/'), NULL, GNOME_APP_PIXMAP_STOCK,
565 	       GNOME_STOCK_MENU_ABOUT, '/',0
566 	   },
567 	   GNOMEUIINFO_END
568 };
569 
570 GnomeUIInfo mainmenu[] = {
571 	    GNOMEUIINFO_MENU_GAME_TREE(game_tree),
572 	    GNOMEUIINFO_MENU_EDIT_TREE(edit_menu),
573 	    { GNOME_APP_UI_SUBTREE, N_("Apparel"), NULL, apparel_menu, NULL,
574 		NULL, 0, NULL, 0, 0, NULL },
575 	    { GNOME_APP_UI_SUBTREE, N_("Action"), NULL, action_menu, NULL,
576 		NULL, 0, NULL, 0, 0, NULL },
577 	    { GNOME_APP_UI_SUBTREE, N_("Magic"), NULL, magic_menu, NULL,
578 		NULL, 0, NULL, 0, 0, NULL },
579 	    GNOMEUIINFO_MENU_HELP_TREE(help_menu),
580 	    GNOMEUIINFO_END
581 };
582 
583 static void
ghack_main_window_key_press(GtkWidget * widget,GdkEventKey * event,gpointer data)584 ghack_main_window_key_press(GtkWidget *widget, GdkEventKey *event,
585 	gpointer data)
586 {
587     /* First, turn off the key press propogation.  We've got the
588      * key, but we don't wan't the underlying Gtk widgets to get it,
589      * since they do the wrong thing with the arrow keys (shift focus)... */
590     gtk_signal_emit_stop_by_name( GTK_OBJECT(mainWindow), "key_press_event");
591 
592     /* stuff the key event into the keybuffer */
593     ghack_handle_key_press(widget, event, data);
594 }
595 
596 
597 /* parsing args */
598 void
parse_args(int argc,char * argv[])599 parse_args (int argc, char *argv[])
600 {
601   gint ch;
602 
603   struct option options[] = {
604 	/* Default args */
605 	{ "help",		no_argument,            NULL,   'h'     },
606 	{ "version",	 	no_argument,            NULL,   'v'     },
607 
608 	{ NULL, 0, NULL, 0 }
609 	};
610 
611   gchar *id = NULL;
612 
613   /* initialize getopt */
614   optarg = NULL;
615   optind = 0;
616   optopt = 0;
617 
618   while( (ch = getopt_long(argc, argv, "hv", options, NULL)) != EOF )
619   {
620     switch(ch)
621     {
622       case 'h':
623         g_print (
624       	  _("%s: A gnomified 'Hello World' program\n\n"
625       	    "Usage: %s [--help] [--version]\n\n"
626       	    "Options:\n"
627       	    "        --help     display this help and exit\n"
628       	    "        --version  output version information and exit\n"),
629       	    argv[0], argv[0]);
630         exit(0);
631         break;
632       case 'v':
633         g_print (_("NetHack %s.\n"), VERSION_STRING);
634         exit(0);
635         break;
636       case ':':
637       case '?':
638         g_print (_("Options error\n"));
639         exit(0);
640         break;
641     }
642   }
643 
644   /* SM stuff */
645   session_id = gnome_client_new ();
646 #if 0
647   session_id = gnome_client_new (
648   	/* callback to save the state and parameter for it */
649   	save_state, argv[0],
650   	/* callback to die and parameter for it */
651     	NULL, NULL,
652 	/* id from the previous session if restarted, NULL otherwise */
653        	id);
654 #endif
655   /* set the program name */
656   gnome_client_set_program (session_id, argv[0]);
657   g_free(id);
658 
659   return;
660 }
661 
662 /*
663  * [ALI] Gnome installs its own handler(s) for SIGBUS, SIGFPE and SIGSEGV.
664  * These handlers will fork and exec a helper program. When that helper
665  * comes to initialize GTK+, it may fail if setuid/setgid. We solve this
666  * by dropping privileges before passing the signal along the chain.
667  * Note: We don't need to either drop or mask the saved ID since this
668  * will be reset when the child process performs the execve() anyway.
669  */
670 
671 static struct {
672     int signum;
673     void (*handler)(int);
674 } ghack_chain[] = {
675     {SIGBUS},
676     {SIGFPE},
677     {SIGSEGV},
678     {SIGILL}		/* Not currently handled by Gnome */
679 };
680 
ghack_sig_handler(int signum)681 static void ghack_sig_handler(int signum)
682 {
683     int i;
684     uid_t uid, euid;
685     gid_t gid, egid;
686     uid = getuid();
687     euid = geteuid();
688     gid = getgid();
689     egid = getegid();
690     if (gid != egid)
691 	setgid(gid);
692     if (uid != euid)
693 	setuid(uid);
694     for(i = SIZE(ghack_chain) - 1; i >= 0; i--)
695 	if (ghack_chain[i].signum == signum) {
696 	    ghack_chain[i].handler(signum);
697 	    break;
698 	}
699     if (i < 0)
700 	impossible("Unhandled ghack signal");
701     if (uid != euid)
702 	setuid(euid);
703     if (gid != egid)
704 	setgid(egid);
705 }
706 
707 /* initialize gnome and fir up the main window */
ghack_init_main_window(int argc,char ** argv)708 void ghack_init_main_window( int argc, char** argv)
709 {
710     int i;
711     struct timeval tv;
712     uid_t uid, euid;
713 
714     /* It seems that the authors of gnome_score_init() drop group
715      * priveledges.  We need group priveledges, so until we change the
716      * way we save games to do things the gnome way(???), this stays
717      * commented out.  (after hours of frusteration...)
718      *  -Erik
719      */
720     /* gnome_score_init("gnomehack"); */
721 
722     gettimeofday(&tv, NULL);
723     srand(tv.tv_usec);
724 
725     uid = getuid();
726     euid = geteuid();
727     if (uid != euid)
728       setuid(uid);
729     hide_privileges(TRUE);
730     /* XXX gnome_init must print nethack options for --help, but does not */
731     gnome_init ("nethack", VERSION_STRING, argc, argv);
732     hide_privileges(FALSE);
733     parse_args (argc, argv);
734 
735     /* Initialize the i18n stuff (not that gnomehack supperts it yet...) */
736 #if 0
737     textdomain (PACKAGE);
738 #endif
739     gdk_imlib_init();
740 
741     /* Main window */
742     mainWindow = gnome_app_new((char *) "nethack",
743 	    (char *) N_("Nethack for Gnome"));
744     gtk_widget_realize(mainWindow);
745     if (restarted) {
746 	gtk_widget_set_uposition (mainWindow, os_x, os_y);
747 	gtk_widget_set_usize     (mainWindow, os_w, os_h);
748     }
749     gtk_window_set_default_size( GTK_WINDOW(mainWindow), 800, 600);
750     gtk_window_set_policy(GTK_WINDOW(mainWindow), FALSE, TRUE, TRUE);
751     gnome_app_create_menus(GNOME_APP(mainWindow), mainmenu);
752     gtk_signal_connect(GTK_OBJECT(mainWindow), "key_press_event",
753 	    GTK_SIGNAL_FUNC(ghack_main_window_key_press), NULL);
754     gtk_signal_connect(GTK_OBJECT(mainWindow), "delete_event",
755 	    GTK_SIGNAL_FUNC(ghack_quit_game_cb), NULL);
756 
757     /* Put some stuff into our main window */
758     vBoxMain = gtk_vbox_new (FALSE, 0);
759     hBoxFirstRow = gtk_hbox_new (FALSE, 0);
760 
761     /* pack Boxes into other boxes to produce the right structure */
762     gtk_box_pack_start (GTK_BOX (vBoxMain), hBoxFirstRow, FALSE, TRUE, 0);
763 
764     /* pack vBoxMain which contains all our widgets into the main window. */
765     gnome_app_set_contents(GNOME_APP(mainWindow), vBoxMain);
766 
767     /* DONT show the main window yet, due to a Gtk bug that causes it
768      * to not refresh the window when adding widgets after the window
769      * has already been shown */
770     if (uid != euid)
771       setuid(euid);
772     for(i = 0; i < SIZE(ghack_chain); i++)
773 	ghack_chain[i].handler =
774 	  signal(ghack_chain[i].signum, ghack_sig_handler);
775 }
776 
ghack_main_window_add_map_window(GtkWidget * win)777 void ghack_main_window_add_map_window(GtkWidget* win)
778 {
779     GtkWidget *vBox;
780 
781     vBox= gtk_vbox_new (TRUE, 0);
782     gtk_box_pack_start (GTK_BOX (vBox), win, TRUE, TRUE, 2);
783     gtk_box_pack_start (GTK_BOX (vBoxMain), vBox, TRUE, TRUE, 2);
784     gtk_widget_show_all(vBox);
785     /* Ok, now show the main window -- now that we have added in
786      * all the windows (relys on nethack displaying the map window last
787      * (This is an ugly kludge, BTW)
788      */
789     gtk_widget_show_all(mainWindow);
790 }
791 
792 void
ghack_main_window_add_message_window(GtkWidget * win)793 ghack_main_window_add_message_window(GtkWidget* win)
794 {
795     gtk_box_pack_start (GTK_BOX (hBoxFirstRow), win, TRUE, TRUE, 2);
796     gtk_widget_show_all(win);
797 }
798 
799 void
ghack_main_window_add_status_window(GtkWidget * win)800 ghack_main_window_add_status_window(GtkWidget* win)
801 {
802     gtk_box_pack_start (GTK_BOX (hBoxFirstRow), win, FALSE, TRUE, 2);
803     gtk_widget_show_all(win);
804 }
805 
806 void
ghack_main_window_add_worn_window(GtkWidget * win)807 ghack_main_window_add_worn_window(GtkWidget* win)
808 {
809     gtk_box_pack_end (GTK_BOX (hBoxFirstRow), win, FALSE, TRUE, 2);
810     gtk_widget_show_all(win);
811 }
812 
813 void
ghack_main_window_add_text_window(GtkWidget * win)814 ghack_main_window_add_text_window(GtkWidget *win)
815 {
816   g_warning("Fixme!!! AddTextWindow is not yet implemented");
817 }
818 
819 void
ghack_main_window_remove_window(GtkWidget * win)820 ghack_main_window_remove_window(GtkWidget *win)
821 {
822   g_warning("Fixme!!! RemoveWindow is not yet implemented");
823 }
824 
825 void
ghack_main_window_update_inventory()826 ghack_main_window_update_inventory()
827 {
828 /* For now, do very little.  Eventually we may allow the inv. window
829      to stay active.  When we do this, we'll need to implement this...
830    g_warning("Fixme!!! updateInventory is not yet implemented");
831 */
832 	gnome_display_nhwindow(WIN_WORN, FALSE);
833 }
834 
835 GtkWidget*
ghack_get_main_window()836 ghack_get_main_window()
837 {
838       return( GTK_WIDGET(mainWindow) );
839 }
840