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