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