OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / win / gnome / gnsignal.c
1 /* NetHack 3.6  gnsignal.c      $NHDT-Date: 1432512805 2015/05/25 00:13:25 $  $NHDT-Branch: master $:$NHDT-Revision: 1.11 $ */
2 /* Copyright (C) 1998 by Anthony Taylor <tonyt@ptialaska.net> */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "gnsignal.h"
6 #include "gnmain.h"
7 #include <gdk/gdkkeysyms.h>
8
9 GList *g_keyBuffer;
10 GList *g_clickBuffer;
11 int g_numKeys = 0;
12 int g_numClicks = 0;
13 int g_askingQuestion = 0;
14 static int s_done = FALSE;
15
16 /*
17  * ghack_init_signals
18  *
19  * Create some signals and attach them to the GtkWidget class.
20  * These are the signals:
21  *
22  *      ghack_curs        : NONE:INT,INT
23  *                            INT 1 = x
24  *                            INT 2 = y
25  *
26  *      ghack_putstr      : NONE:INT,POINTER
27  *                            INT     = attribute
28  *                            POINTER = char* string to print
29  *
30  *      ghack_print_glyph : NONE:INT,INT,POINTER
31  *                            INT 1 = x
32  *                            INT 2 = y
33  *                            INT 3 = GtkPixmap* to rendered glyph
34  *
35  *      ghack_clear       : NONE:NONE
36  *
37  *      ghack_display     : NONE:BOOL
38  *                            BOOL  = blocking flag
39  *
40  *      ghack_start_menu  : NONE:NONE
41  *
42  *      ghack_add_menu    : NONE:POINTER
43  *                            POINTER = GHackMenuItem*
44  *
45  *      ghack_end_menu    : NONE:POINTER
46  *                            POINTER = char* to closing string
47  *
48  *      ghack_select_menu : NONE:POINTER,INT,POINTER
49  *                            POINTER    = int pointer-- filled with number
50  *                                         of selected items on return
51  *                            INT        = number of items selected
52  *                            POINTER    = structure to fill
53  *
54  *      ghack_cliparound  : NONE:INT,INT
55  *                            INT 1 = x
56  *                            INT 2 = y
57 */
58
59 void
60 ghack_init_signals(void)
61 {
62     ghack_signals[GHSIG_CURS] = gtk_object_class_user_signal_new(
63         gtk_type_class(gtk_widget_get_type()), "ghack_curs", GTK_RUN_FIRST,
64         gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT,
65         GTK_TYPE_INT);
66
67     ghack_signals[GHSIG_PUTSTR] = gtk_object_class_user_signal_new(
68         gtk_type_class(gtk_widget_get_type()), "ghack_putstr", GTK_RUN_FIRST,
69         gtk_marshal_NONE__INT_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_INT,
70         GTK_TYPE_POINTER);
71
72     ghack_signals[GHSIG_PRINT_GLYPH] = gtk_object_class_user_signal_new(
73         gtk_type_class(gtk_widget_get_type()), "ghack_print_glyph",
74         GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT_POINTER, GTK_TYPE_NONE, 3,
75         GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
76
77     ghack_signals[GHSIG_CLEAR] = gtk_object_class_user_signal_new(
78         gtk_type_class(gtk_widget_get_type()), "ghack_clear", GTK_RUN_FIRST,
79         gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
80
81     ghack_signals[GHSIG_DISPLAY] = gtk_object_class_user_signal_new(
82         gtk_type_class(gtk_widget_get_type()), "ghack_display", GTK_RUN_FIRST,
83         gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1, GTK_TYPE_BOOL);
84
85     ghack_signals[GHSIG_START_MENU] = gtk_object_class_user_signal_new(
86         gtk_type_class(gtk_widget_get_type()), "ghack_start_menu",
87         GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
88
89     ghack_signals[GHSIG_ADD_MENU] = gtk_object_class_user_signal_new(
90         gtk_type_class(gtk_widget_get_type()), "ghack_add_menu",
91         GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
92         GTK_TYPE_POINTER);
93
94     ghack_signals[GHSIG_END_MENU] = gtk_object_class_user_signal_new(
95         gtk_type_class(gtk_widget_get_type()), "ghack_end_menu",
96         GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1,
97         GTK_TYPE_POINTER);
98
99     ghack_signals[GHSIG_SELECT_MENU] = gtk_object_class_user_signal_new(
100         gtk_type_class(gtk_widget_get_type()), "ghack_select_menu",
101         GTK_RUN_FIRST, gtk_marshal_NONE__POINTER_INT_POINTER, GTK_TYPE_NONE,
102         3, GTK_TYPE_POINTER, GTK_TYPE_INT, GTK_TYPE_POINTER);
103
104     ghack_signals[GHSIG_CLIPAROUND] = gtk_object_class_user_signal_new(
105         gtk_type_class(gtk_widget_get_type()), "ghack_cliparound",
106         GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2,
107         GTK_TYPE_INT, GTK_TYPE_INT);
108
109     ghack_signals[GHSIG_FADE_HIGHLIGHT] = gtk_object_class_user_signal_new(
110         gtk_type_class(gtk_widget_get_type()), "ghack_fade_highlight",
111         GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
112
113     ghack_signals[GHSIG_DELAY] = gtk_object_class_user_signal_new(
114         gtk_type_class(gtk_widget_get_type()), "gnome_delay_output",
115         GTK_RUN_FIRST, gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT);
116 }
117
118 /* For want of a better place, I'm putting the delay output stuff here
119  *   -Erik
120  */
121 static gint
122 timeout_callback(gpointer data)
123 {
124     s_done = TRUE;
125     return FALSE;
126 }
127
128 void
129 ghack_delay(GtkWidget *win, int numMillisecs, gpointer data)
130 {
131     s_done = FALSE;
132     gtk_timeout_add((unsigned int) numMillisecs, timeout_callback, NULL);
133     while (s_done == FALSE)
134         gtk_main_iteration();
135 }
136
137 void
138 ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event,
139                           gpointer data)
140 {
141     GHClick *click;
142     double x1, y1;
143
144     if (event->type != GDK_BUTTON_PRESS)
145         return;
146
147     gnome_canvas_window_to_world(GNOME_CANVAS(widget), event->x, event->y,
148                                  &x1, &y1);
149     /*
150         g_message("I got a click at %f,%f with button %d \n",
151                 x1, y1, event->button);
152     */
153
154     /* We allocate storage here, so we need to remember if (g_numClicks>0)
155      * to blow this away when closing the app using something like
156      *  while (g_clickBuffer)
157      *       {
158      *          g_free((GHClick)g_clickBuffer->data);
159      *          g_clickBuffer = g_clickBuffer->next;
160      *       }
161      *  g_list_free( g_clickBuffer );
162      *
163      */
164     click = g_new(GHClick, 1);
165
166     click->x = (int) x1 / ghack_glyph_width();
167     click->y = (int) y1 / ghack_glyph_height();
168     click->mod = (event->button == 1) ? CLICK_1 : CLICK_2;
169
170     g_clickBuffer = g_list_prepend(g_clickBuffer, click);
171     /* Could use g_list_length(), but it is stupid and just
172      * traverses the list while counting, so we'll just do
173      * the counting ourselves in advance. */
174     g_numClicks++;
175 }
176
177 #ifndef M
178 #ifndef NHSTDC
179 #define M(c) (0x80 | (c))
180 #else
181 #define M(c) ((c) -128)
182 #endif /* NHSTDC */
183 #endif
184 #ifndef C
185 #define C(c) (0x1f & (c))
186 #endif
187
188 void
189 ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
190 {
191     static int was_pound = 0;
192     int key = 0;
193     int ctl = GDK_CONTROL_MASK;
194     int alt = GDK_MOD1_MASK;
195
196 /* Turn this on to debug key events */
197 #if 0
198     g_message("I got a \"%s\" key (%d) %s%s", 
199               gdk_keyval_name (event->keyval), event->keyval, 
200               (event->state&ctl)? "+CONTROL":"", (event->state&alt)? "+ALT":"");
201 #endif
202
203     switch (event->keyval) {
204     /* special keys to do stuff with */
205
206     /* Set up the direction keys */
207
208     /* First handle the arrow keys -- these always mean move */
209     case GDK_Right:
210     case GDK_rightarrow:
211         key = Cmd.move_E;
212         break;
213     case GDK_Left:
214     case GDK_leftarrow:
215         key = Cmd.move_W;
216         break;
217     case GDK_Up:
218     case GDK_uparrow:
219         key = Cmd.move_N;
220         break;
221     case GDK_Down:
222     case GDK_downarrow:
223         key = Cmd.move_S;
224         break;
225     case GDK_Home:
226         key = Cmd.move_NW;
227         break;
228     case GDK_End:
229         key = Cmd.move_SW;
230         break;
231     case GDK_Page_Down:
232         key = Cmd.move_SE;
233         break;
234     case GDK_Page_Up:
235         key = Cmd.move_NE;
236         break;
237     case ' ':
238         key = '.';
239         break;
240
241     /* Now, handle the numberpad (move or numbers) */
242     case GDK_KP_Right:
243     case GDK_KP_6:
244         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
245             && iflags.num_pad)
246             key = GDK_KP_6;
247         else
248             key = '6';
249         break;
250
251     case GDK_KP_Left:
252     case GDK_KP_4:
253         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
254             && iflags.num_pad)
255             key = GDK_KP_4;
256         else
257             key = '4';
258         break;
259
260     case GDK_KP_Up:
261     case GDK_KP_8:
262         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
263             && iflags.num_pad)
264             key = GDK_KP_8;
265         else
266             key = '8';
267         break;
268
269     case GDK_KP_Down:
270     case GDK_KP_2:
271         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
272             && iflags.num_pad)
273             key = GDK_KP_2;
274         else
275             key = '2';
276         break;
277
278     /* Move Top-Left */
279     case GDK_KP_Home:
280     case GDK_KP_7:
281         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
282             && iflags.num_pad)
283             key = GDK_KP_7;
284         else
285             key = '7';
286         break;
287
288     case GDK_KP_Page_Up:
289     case GDK_KP_9:
290         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
291             && iflags.num_pad)
292             key = GDK_KP_9;
293         else
294             key = '9';
295         break;
296
297     case GDK_KP_End:
298     case GDK_KP_1:
299         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
300             && iflags.num_pad)
301             key = GDK_KP_1;
302         else
303             key = '1';
304         break;
305
306     case GDK_KP_Page_Down:
307     case GDK_KP_3:
308         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
309             && iflags.num_pad)
310             key = GDK_KP_3;
311         else
312             key = '3';
313         break;
314
315     case GDK_KP_5:
316         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)
317             && iflags.num_pad)
318             key = GDK_KP_5;
319         else
320             key = '5';
321         break;
322
323     case GDK_KP_Delete:
324     case GDK_KP_Decimal:
325         key = '.';
326         break;
327
328     /* can't just ignore "#", it's a core feature */
329     case GDK_numbersign:
330         key = '#';
331         break;
332
333     /* We will probably want to do something with these later... */
334     case GDK_KP_Begin:
335     case GDK_KP_F1:
336     case GDK_F1:
337     case GDK_KP_F2:
338     case GDK_F2:
339     case GDK_KP_F3:
340     case GDK_F3:
341     case GDK_KP_F4:
342     case GDK_F4:
343     case GDK_F5:
344     case GDK_F6:
345     case GDK_F7:
346     case GDK_F8:
347     case GDK_F9:
348     case GDK_F10:
349     case GDK_F11:
350     case GDK_F12:
351         break;
352     /* various keys to ignore */
353     case GDK_KP_Insert:
354     case GDK_Insert:
355     case GDK_Delete:
356     case GDK_Print:
357     case GDK_BackSpace:
358     case GDK_Pause:
359     case GDK_Scroll_Lock:
360     case GDK_Shift_Lock:
361     case GDK_Num_Lock:
362     case GDK_Caps_Lock:
363     case GDK_Control_L:
364     case GDK_Control_R:
365     case GDK_Shift_L:
366     case GDK_Shift_R:
367     case GDK_Alt_L:
368     case GDK_Alt_R:
369     case GDK_Meta_L:
370     case GDK_Meta_R:
371     case GDK_Mode_switch:
372     case GDK_Multi_key:
373         return;
374
375     default:
376         key = event->keyval;
377         break;
378     }
379
380     if ((event->state & alt) || was_pound) {
381         key = M(event->keyval);
382     } else if (event->state & ctl) {
383         key = C(event->keyval);
384     }
385     if (was_pound) {
386         was_pound = 0;
387     }
388
389     /* Ok, here is where we do clever stuff to overide the default
390      * game behavior */
391     if (g_askingQuestion == 0) {
392         if (key == 'S' || key == M('S') || key == C('S')) {
393             ghack_save_game_cb(NULL, NULL);
394             return;
395         }
396     }
397     g_keyBuffer = g_list_prepend(g_keyBuffer, GINT_TO_POINTER(key));
398     g_numKeys++;
399 }