OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / win / gnome / gnsignal.c
1 /*      SCCS Id: @(#)gnsignal.c 3.4     2000/07/16      */
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] =
63     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
64                                       "ghack_curs",
65                                       GTK_RUN_FIRST,
66                                       gtk_marshal_NONE__INT_INT,
67                                       GTK_TYPE_NONE,
68                                       2,
69                                       GTK_TYPE_INT,
70                                       GTK_TYPE_INT);  
71
72   ghack_signals[GHSIG_PUTSTR] =
73     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
74                                       "ghack_putstr",
75                                       GTK_RUN_FIRST,
76                                       gtk_marshal_NONE__INT_POINTER,
77                                       GTK_TYPE_NONE,
78                                       2,
79                                       GTK_TYPE_INT,
80                                       GTK_TYPE_POINTER);
81
82   ghack_signals[GHSIG_PRINT_GLYPH] =
83     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
84                                       "ghack_print_glyph",
85                                       GTK_RUN_FIRST,
86                                       gtk_marshal_NONE__INT_INT_POINTER,
87                                       GTK_TYPE_NONE,
88                                       3,
89                                       GTK_TYPE_INT,
90                                       GTK_TYPE_INT,
91                                       GTK_TYPE_POINTER);
92
93   ghack_signals[GHSIG_CLEAR] =
94     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
95                                       "ghack_clear",
96                                       GTK_RUN_FIRST,
97                                       gtk_marshal_NONE__NONE,
98                                       GTK_TYPE_NONE,
99                                       0);
100   
101   ghack_signals[GHSIG_DISPLAY] =
102     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
103                                       "ghack_display",
104                                       GTK_RUN_FIRST,
105                                       gtk_marshal_NONE__BOOL,
106                                       GTK_TYPE_NONE,
107                                       1,
108                                       GTK_TYPE_BOOL);
109   
110   ghack_signals[GHSIG_START_MENU] =
111     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
112                                       "ghack_start_menu",
113                                       GTK_RUN_FIRST,
114                                       gtk_marshal_NONE__NONE,
115                                       GTK_TYPE_NONE,
116                                       0);
117   
118   ghack_signals[GHSIG_ADD_MENU] =
119     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
120                                       "ghack_add_menu",
121                                       GTK_RUN_FIRST,
122                                       gtk_marshal_NONE__POINTER,
123                                       GTK_TYPE_NONE,
124                                       1,
125                                       GTK_TYPE_POINTER);
126   
127   ghack_signals[GHSIG_END_MENU] =
128     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
129                                       "ghack_end_menu",
130                                       GTK_RUN_FIRST,
131                                       gtk_marshal_NONE__POINTER,
132                                       GTK_TYPE_NONE,
133                                       1,
134                                       GTK_TYPE_POINTER);
135   
136   ghack_signals[GHSIG_SELECT_MENU] =
137     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
138                                       "ghack_select_menu",
139                                       GTK_RUN_FIRST,
140                                       gtk_marshal_NONE__POINTER_INT_POINTER,
141                                       GTK_TYPE_NONE,
142                                       3,
143                                       GTK_TYPE_POINTER,
144                                       GTK_TYPE_INT,
145                                       GTK_TYPE_POINTER);
146   
147   ghack_signals[GHSIG_CLIPAROUND] =
148     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
149                                       "ghack_cliparound",
150                                       GTK_RUN_FIRST,
151                                       gtk_marshal_NONE__INT_INT,
152                                       GTK_TYPE_NONE,
153                                       2,
154                                       GTK_TYPE_INT,
155                                       GTK_TYPE_INT);
156
157   ghack_signals[GHSIG_FADE_HIGHLIGHT] =
158     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
159                                       "ghack_fade_highlight",
160                                       GTK_RUN_FIRST,
161                                       gtk_marshal_NONE__NONE,
162                                       GTK_TYPE_NONE,
163                                       0);
164   
165   ghack_signals[GHSIG_DELAY] =
166     gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()),
167                                       "gnome_delay_output",
168                                       GTK_RUN_FIRST,
169                                       gtk_marshal_NONE__INT,
170                                       GTK_TYPE_NONE,
171                                       1,
172                                       GTK_TYPE_INT);
173   
174 }
175
176 /* For want of a better place, I'm putting the delay output stuff here
177  *   -Erik
178  */
179 static gint timeout_callback(gpointer data)
180 {
181     s_done=TRUE;
182     return FALSE;
183 }
184
185 void
186 ghack_delay( GtkWidget *win, int numMillisecs, gpointer data)
187 {
188     s_done=FALSE;
189     gtk_timeout_add( (unsigned int) numMillisecs, 
190             timeout_callback, NULL);
191     while( s_done==FALSE)
192         gtk_main_iteration();
193 }
194
195
196 void 
197 ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, 
198         gpointer data)
199 {
200     GHClick *click;
201     double x1, y1;
202
203     if (event->type != GDK_BUTTON_PRESS)
204         return;
205     
206     gnome_canvas_window_to_world( GNOME_CANVAS( widget), event->x, 
207             event->y, &x1, &y1);
208 /*
209     g_message("I got a click at %f,%f with button %d \n", 
210             x1, y1, event->button);
211 */
212
213     /* We allocate storage here, so we need to remember if (g_numClicks>0)
214      * to blow this away when closing the app using something like 
215      *  while (g_clickBuffer)
216      *       {
217      *          g_free((GHClick)g_clickBuffer->data);
218      *          g_clickBuffer = g_clickBuffer->next;
219      *       }
220      *  g_list_free( g_clickBuffer );
221      *
222      */
223     click = g_new( GHClick, 1);
224     
225     click->x=(int)x1/ghack_glyph_width();
226     click->y=(int)y1/ghack_glyph_height();
227     click->mod=(event->button == 1)? CLICK_1 : CLICK_2;
228     
229     g_clickBuffer = g_list_prepend (g_clickBuffer, click);
230     /* Could use g_list_length(), but it is stupid and just
231      * traverses the list while counting, so we'll just do 
232      * the counting ourselves in advance. */
233     g_numClicks++;
234 }
235
236 #ifndef M
237 # ifndef NHSTDC
238 #  define M(c)          (0x80 | (c))
239 # else
240 #  define M(c)          ((c) - 128)
241 # endif /* NHSTDC */
242 #endif
243 #ifndef C
244 #define C(c)            (0x1f & (c))
245 #endif
246
247
248 void 
249 ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
250 {
251     static int was_pound = 0;
252     int key = 0;
253     int ctl = GDK_CONTROL_MASK;
254     int alt = GDK_MOD1_MASK;
255
256     /* Turn this on to debug key events */
257 #if 0
258     g_message("I got a \"%s\" key (%d) %s%s", 
259               gdk_keyval_name (event->keyval), event->keyval, 
260               (event->state&ctl)? "+CONTROL":"", (event->state&alt)? "+ALT":"");
261 #endif
262
263     switch (event->keyval) {
264         /* special keys to do stuff with */
265
266         /* Set up the direction keys */
267
268         /* First handle the arrow keys -- these always mean move */
269     case GDK_Right:
270     case GDK_rightarrow:
271         if (iflags.num_pad) key='6'; else  key='l'; break;
272     case GDK_Left:
273     case GDK_leftarrow:
274         if (iflags.num_pad) key='4'; else  key='h'; break;
275     case GDK_Up:
276     case GDK_uparrow:
277         if (iflags.num_pad) key='8'; else  key='k'; break;
278     case GDK_Down:
279     case GDK_downarrow:
280         if (iflags.num_pad) key='2'; else  key='j'; break;
281     case GDK_Home:
282         if (iflags.num_pad) key='7'; else  key='y'; break;
283     case GDK_End:
284         if (iflags.num_pad) key='1'; else  key='b'; break;
285     case GDK_Page_Down:
286         if (iflags.num_pad) key='3'; else  key='n'; break;
287     case GDK_Page_Up:
288         if (iflags.num_pad) key='9'; else  key='u'; break;
289     case ' ':            key='.'; break;
290
291         /* Now, handle the numberpad (move or numbers) */
292     case GDK_KP_Right:
293     case GDK_KP_6:
294         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
295             key = GDK_KP_6;
296         else
297             key='6'; 
298         break;
299
300     case GDK_KP_Left:
301     case GDK_KP_4:
302         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
303             key = GDK_KP_4;
304         else
305             key='4'; 
306         break;
307
308     case GDK_KP_Up:
309     case GDK_KP_8:
310         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
311             key = GDK_KP_8;
312         else
313             key='8'; 
314         break;
315
316     case GDK_KP_Down:
317     case GDK_KP_2:
318         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
319             key = GDK_KP_2;
320         else
321             key='2'; 
322         break;
323
324         /* Move Top-Left */
325     case GDK_KP_Home:
326     case GDK_KP_7:
327         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
328             key = GDK_KP_7;
329         else
330             key='7'; 
331         break;
332
333     case GDK_KP_Page_Up:
334     case GDK_KP_9:
335         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
336             key = GDK_KP_9;
337         else
338             key='9'; 
339         break;
340
341     case GDK_KP_End:
342     case GDK_KP_1:
343         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
344             key = GDK_KP_1;
345         else
346             key='1'; 
347         break;
348
349     case GDK_KP_Page_Down:
350     case GDK_KP_3:
351         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
352             key = GDK_KP_3;
353         else
354             key='3'; 
355         break;
356   
357   
358     case GDK_KP_5:
359         if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad)
360             key = GDK_KP_5;
361         else
362             key='5'; 
363         break;
364
365     case GDK_KP_Delete:
366     case GDK_KP_Decimal:
367         key='.'; 
368         break;
369
370         /* can't just ignore "#", it's a core feature */
371     case GDK_numbersign:
372         key='#';
373         break;
374
375         /* We will probably want to do something with these later... */
376     case GDK_KP_Begin:
377     case GDK_KP_F1:
378     case GDK_F1:
379     case GDK_KP_F2:
380     case GDK_F2:
381     case GDK_KP_F3:
382     case GDK_F3:
383     case GDK_KP_F4:
384     case GDK_F4:
385     case GDK_F5:
386     case GDK_F6:
387     case GDK_F7:
388     case GDK_F8:
389     case GDK_F9:
390     case GDK_F10:
391     case GDK_F11:
392     case GDK_F12:
393         break;
394         /* various keys to ignore */
395     case GDK_KP_Insert:
396     case GDK_Insert:
397     case GDK_Delete:
398     case GDK_Print:
399     case GDK_BackSpace:
400     case GDK_Pause:
401     case GDK_Scroll_Lock:
402     case GDK_Shift_Lock:
403     case GDK_Num_Lock:
404     case GDK_Caps_Lock:
405     case GDK_Control_L:
406     case GDK_Control_R:
407     case GDK_Shift_L:
408     case GDK_Shift_R:
409     case GDK_Alt_L:
410     case GDK_Alt_R:
411     case GDK_Meta_L:
412     case GDK_Meta_R:
413     case GDK_Mode_switch:
414     case GDK_Multi_key:
415         return;
416
417     default:
418         key = event->keyval;
419         break;
420     }
421
422     if ((event->state & alt) || was_pound) {
423         key=M(event->keyval);
424     } else if (event->state & ctl) {
425         key=C(event->keyval);
426     }
427     if (was_pound) {
428         was_pound = 0;
429     }
430  
431     /* Ok, here is where we do clever stuff to overide the default
432      * game behavior */
433     if (g_askingQuestion == 0) {
434
435         if (key == 'S' || key == M('S') || key == C('S')) {
436             ghack_save_game_cb( NULL, NULL);
437             return;
438         }
439     }
440     g_keyBuffer = g_list_prepend (g_keyBuffer, GINT_TO_POINTER( key));
441     g_numKeys++;
442 }