771a6cdee361eab0f4f04f72f05deccd7db6fadc
[freeglut] / progs / demos / CallbackMaker / CallbackMaker.c
1 /* CallbackMaker.c */
2 /*
3  * Program to invoke all the callbacks that "freeglut" supports
4  */
5
6
7 #include <GL/freeglut.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11
12 static int sequence_number = 0 ;
13
14 #define CALLBACKMAKER_N_WINDOWS 4
15 int windows[CALLBACKMAKER_N_WINDOWS] = {0};
16
17 /* define status vars showing whether given callback has been called for given window */
18 #define CALLBACK_CALLED_VAR(name)                            int name##_called[CALLBACKMAKER_N_WINDOWS]   = {0};
19 #define CALLBACK_0V(name)                                    int name##_seq[CALLBACKMAKER_N_WINDOWS]      = {-1}; CALLBACK_CALLED_VAR(name); 
20 #define CALLBACK_1V(name,field)                              int name##_##field[CALLBACKMAKER_N_WINDOWS]  = {-1}; CALLBACK_0V(name);
21 #define CALLBACK_2V(name,field1,field2)                      int name##_##field2[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_1V(name,field1);
22 #define CALLBACK_3V(name,field1,field2,field3)               int name##_##field3[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_2V(name,field1,field2);
23 #define CALLBACK_4V(name,field1,field2,field3,field4)        int name##_##field4[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_3V(name,field1,field2,field3);
24 #define CALLBACK_5V(name,field1,field2,field3,field4,field5) int name##_##field5[CALLBACKMAKER_N_WINDOWS] = {-1}; CALLBACK_4V(name,field1,field2,field3,field4);
25 CALLBACK_2V(reshape,width,height);
26 CALLBACK_2V(position,top,left);
27 CALLBACK_1V(visibility,vis);
28 CALLBACK_4V(key,key,x,y,mod);
29 CALLBACK_4V(keyup,key,x,y,mod);
30 CALLBACK_4V(special,key,x,y,mod);
31 CALLBACK_4V(specialup,key,x,y,mod);
32 CALLBACK_4V(joystick,a,b,c,d);
33 CALLBACK_5V(mouse,button,updown,x,y,mod);
34 CALLBACK_5V(mousewheel,number,direction,x,y,mod);
35 CALLBACK_3V(motion,x,y,mod);
36 CALLBACK_3V(passivemotion,x,y,mod);
37 CALLBACK_1V(entry,state);
38 CALLBACK_0V(close);
39 /* menudestroy is registered on each menu, not a window */
40 int menudestroy_called = 0 ;
41 /* menustatus and menustate are global callbacks, set for all menus at the same time */
42 int menustatus_called = 0;
43 int menustate_called = 0;
44
45 #define STRING_LENGTH   10
46
47 static void
48 bitmapPrintf (const char *fmt, ...)
49 {
50     static char buf[256];
51     va_list args;
52
53     va_start(args, fmt);
54 #if defined(WIN32) && !defined(__CYGWIN__)
55     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
56 #else
57     (void) vsnprintf (buf, sizeof(buf), fmt, args);
58 #endif
59     va_end(args);
60     glutBitmapString ( GLUT_BITMAP_HELVETICA_12, (unsigned char*)buf ) ;
61 }
62
63 static int
64 getWindowAndIdx(int *winIdx)
65 {
66     int window = glutGetWindow();
67
68     if (winIdx)
69         (*winIdx) = window==windows[0] ? 0 :
70                     window==windows[1] ? 1 :
71                     window==windows[2] ? 2 : 3;
72
73     return window;
74 }
75
76 static void
77 Mod2Text(int mods, char *text)
78 {
79     if (mods&GLUT_ACTIVE_CTRL)
80         strcat(text,"CTRL");
81     if (mods&GLUT_ACTIVE_SHIFT)
82         if (text[0])
83             strcat(text,"+SHIFT");
84         else
85             strcat(text,"SHIFT");
86     if (mods&GLUT_ACTIVE_ALT)
87         if (text[0])
88             strcat(text,"+ALT");
89         else
90             strcat(text,"ALT");
91
92     if (!text[0])
93         strcat(text,"none");
94 }
95
96 static void 
97 Display(void)
98 {
99   int winIdx;
100   int window = getWindowAndIdx(&winIdx);
101   glClear ( GL_COLOR_BUFFER_BIT );
102
103   glDisable ( GL_DEPTH_TEST );
104   glMatrixMode ( GL_PROJECTION );
105   glPushMatrix();
106   glLoadIdentity();
107   glOrtho(0, glutGet ( GLUT_WINDOW_WIDTH ), 
108           0, glutGet ( GLUT_WINDOW_HEIGHT ), -1, 1 );
109   glMatrixMode ( GL_MODELVIEW );
110   glPushMatrix ();
111   glLoadIdentity ();
112   glColor3ub ( 0, 0, 0 );
113   glRasterPos2i ( 10, glutGet ( GLUT_WINDOW_HEIGHT ) - 20 );    /* 10pt margin above 10pt letters */
114
115   if ( entry_called[winIdx] )
116   {
117     bitmapPrintf ( "Entry %d:  %d\n", entry_seq[winIdx], entry_state[winIdx] );
118   }
119   
120   if ( visibility_called[winIdx] )
121   {
122     bitmapPrintf ( "Visibility %d:  %d\n", visibility_seq[winIdx], visibility_vis[winIdx] );
123   }
124
125   if ( reshape_called[winIdx] )
126   {
127     bitmapPrintf ( "Reshape %d:  %d %d\n", reshape_seq[winIdx], reshape_width[winIdx], reshape_height[winIdx] );
128   }
129
130   if ( position_called[winIdx] )
131   {
132     bitmapPrintf ( "Position %d:  %d %d\n", position_seq[winIdx], position_left[winIdx], position_top[winIdx] );
133   }
134
135   if ( key_called[winIdx] )
136   {
137     char mods[50] = {0};
138     Mod2Text(key_mod[winIdx],mods);
139     bitmapPrintf ( "Key %d:  %d(%c) %d %d (mod: %s)\n", key_seq[winIdx], key_key[winIdx], key_key[winIdx], key_x[winIdx], key_y[winIdx], mods );
140   }
141
142   if ( keyup_called[winIdx] )
143   {
144     char mods[50] = {0};
145     Mod2Text(keyup_mod[winIdx],mods);
146     bitmapPrintf ( "Key Up %d:  %d(%c) %d %d (mod: %s)\n", keyup_seq[winIdx], keyup_key[winIdx], keyup_key[winIdx], keyup_x[winIdx], keyup_y[winIdx], mods );
147   }
148
149   if ( special_called[winIdx] )
150   {
151     char mods[50] = {0};
152     Mod2Text(special_mod[winIdx],mods);
153     bitmapPrintf ( "Special %d:  %d(%c) %d %d (mod: %s)\n", special_seq[winIdx], special_key[winIdx], special_key[winIdx], special_x[winIdx], special_y[winIdx], mods );
154   }
155
156   if ( specialup_called[winIdx] )
157   {
158     char mods[50] = {0};
159     Mod2Text(specialup_mod[winIdx],mods);
160     bitmapPrintf ( "Special Up %d:  %d(%c) %d %d (mod: %s)\n", specialup_seq[winIdx], specialup_key[winIdx], specialup_key[winIdx], specialup_x[winIdx], specialup_y[winIdx], mods );
161   }
162
163   if ( joystick_called[winIdx] )
164   {
165     bitmapPrintf ( "Joystick %d:  %d %d %d %d\n", joystick_seq[winIdx], joystick_a[winIdx], joystick_b[winIdx], joystick_c[winIdx], joystick_d[winIdx] );
166   }
167
168   if ( mouse_called[winIdx] )
169   {
170     char mods[50] = {0};
171     Mod2Text(mouse_mod[winIdx],mods);
172     bitmapPrintf ( "Mouse %d:  %d %d %d %d (mod: %s)\n", mouse_seq[winIdx], mouse_button[winIdx], mouse_updown[winIdx], mouse_x[winIdx], mouse_y[winIdx], mods );
173   }
174
175   if ( mousewheel_called[winIdx] )
176   {
177     char mods[50] = {0};
178     Mod2Text(mousewheel_mod[winIdx],mods);
179     bitmapPrintf ( "Mouse Wheel %d:  %d %d %d %d (mod: %s)\n", mousewheel_seq[winIdx], mousewheel_number[winIdx], mousewheel_direction[winIdx], mousewheel_x[winIdx], mousewheel_y[winIdx], mods );
180   }
181
182   if ( motion_called[winIdx] )
183   {
184     char mods[50] = {0};
185     Mod2Text(motion_mod[winIdx],mods);
186     bitmapPrintf ( "Motion %d:  %d %d (mod: %s)\n", motion_seq[winIdx], motion_x[winIdx], motion_y[winIdx], mods );
187   }
188
189   if ( passivemotion_called[winIdx] )
190   {
191     char mods[50] = {0};
192     Mod2Text(passivemotion_mod[winIdx],mods);
193     bitmapPrintf ( "Passive Motion %d:  %d %d (mod: %s)\n", passivemotion_seq[winIdx], passivemotion_x[winIdx], passivemotion_y[winIdx], mods );
194   }
195
196   glMatrixMode ( GL_PROJECTION );
197   glPopMatrix ();
198   glMatrixMode ( GL_MODELVIEW );
199   glPopMatrix ();
200   glEnable ( GL_DEPTH_TEST );
201
202   printf ( "%6d Window %d Display Callback\n",
203             ++sequence_number, window ) ;
204   glutSwapBuffers();
205 }
206
207 static void
208 Warning(const char *fmt, va_list ap)
209 {
210     printf("%6d Warning callback:\n");
211
212     /* print warning message */
213     vprintf(fmt, ap);
214 }
215
216 static void
217 Error(const char *fmt, va_list ap)
218 {
219     char dummy_string[STRING_LENGTH];
220     printf("%6d Error callback:\n");
221
222     /* print warning message */
223     vprintf(fmt, ap);
224
225     /* terminate program, after pause for input so user can see */
226     printf ( "Please enter something to exit: " );
227     fgets ( dummy_string, STRING_LENGTH, stdin );
228
229     /* Call exit directly as freeglut is messed
230      * up internally when an error is called. 
231      */
232     exit(1);
233 }
234
235 static void 
236 Visibility(int vis)
237 {
238   int winIdx;
239   int window = getWindowAndIdx(&winIdx);
240   printf ( "%6d Window %d Visibility Callback:  %d\n",
241             ++sequence_number, window, vis ) ;
242   visibility_called[winIdx] = 1 ;
243   visibility_vis[winIdx] = vis ;
244   visibility_seq[winIdx] = sequence_number ;
245   glutPostRedisplay () ;
246 }
247
248 static void 
249 Reshape(int width, int height)
250 {
251   int winIdx;
252   int window = getWindowAndIdx(&winIdx);
253   printf ( "%6d Window %d Reshape Callback:  %d %d\n",
254             ++sequence_number, window, width, height ) ;
255   reshape_called[winIdx] = 1 ;
256   reshape_width[winIdx] = width ;
257   reshape_height[winIdx] = height ;
258   reshape_seq[winIdx] = sequence_number ;
259   glViewport(0,0,width,height);
260   glutPostRedisplay () ;
261 }
262
263 static void 
264 Position(int left, int top)
265 {
266   int winIdx;
267   int window = getWindowAndIdx(&winIdx);
268   printf ( "%6d Window %d Position Callback:  %d %d\n",
269             ++sequence_number, window, left, top ) ;
270   position_called[winIdx] = 1 ;
271   position_left[winIdx] = left ;
272   position_top[winIdx] = top ;
273   position_seq[winIdx] = sequence_number ;
274   glutPostRedisplay () ;
275 }
276
277 static void 
278 Key(unsigned char key, int x, int y)
279 {
280   int winIdx;
281   int window = getWindowAndIdx(&winIdx);
282   printf ( "%6d Window %d Keyboard Callback:  %d %d %d\n",
283             ++sequence_number, window, key, x, y ) ;
284   key_called[winIdx] = 1 ;
285   key_key[winIdx] = key ;
286   key_x[winIdx] = x ;
287   key_y[winIdx] = y ;
288   key_seq[winIdx] = sequence_number ;
289   key_mod[winIdx] = glutGetModifiers() ;
290   glutPostRedisplay () ;
291 }
292
293 static void 
294 KeyUp(unsigned char key, int x, int y)
295 {
296   int winIdx;
297   int window = getWindowAndIdx(&winIdx);
298   printf ( "%6d Window %d Key Release Callback:  %d %d %d\n",
299             ++sequence_number, window, key, x, y ) ;
300   keyup_called[winIdx] = 1 ;
301   keyup_key[winIdx] = key ;
302   keyup_x[winIdx] = x ;
303   keyup_y[winIdx] = y ;
304   keyup_seq[winIdx] = sequence_number ;
305   keyup_mod[winIdx] = glutGetModifiers() ;
306   glutPostRedisplay () ;
307 }
308
309 static void 
310 Special(int key, int x, int y)
311 {
312   int winIdx;
313   int window = getWindowAndIdx(&winIdx);
314   printf ( "%6d Window %d Special Key Callback:  %d %d %d\n",
315             ++sequence_number, window, key, x, y ) ;
316   special_called[winIdx] = 1 ;
317   special_key[winIdx] = key ;
318   special_x[winIdx] = x ;
319   special_y[winIdx] = y ;
320   special_seq[winIdx] = sequence_number ;
321   special_mod[winIdx] = glutGetModifiers() ;
322   glutPostRedisplay () ;
323 }
324
325 static void 
326 SpecialUp(int key, int x, int y)
327 {
328   int winIdx;
329   int window = getWindowAndIdx(&winIdx);
330   printf ( "%6d Window %d Special Key Release Callback:  %d %d %d\n",
331             ++sequence_number, window, key, x, y ) ;
332   specialup_called[winIdx] = 1 ;
333   specialup_key[winIdx] = key ;
334   specialup_x[winIdx] = x ;
335   specialup_y[winIdx] = y ;
336   specialup_seq[winIdx] = sequence_number ;
337   specialup_mod[winIdx] = glutGetModifiers() ;
338   glutPostRedisplay () ;
339 }
340
341 static void 
342 Joystick( unsigned int a, int b, int c, int d)  /* Need meaningful names */
343 {
344   int winIdx;
345   int window = getWindowAndIdx(&winIdx);
346   printf ( "%6d Window %d Joystick Callback:  %d %d %d %d\n",
347             ++sequence_number, window, a, b, c, d ) ;
348   joystick_called[winIdx] = 1 ;
349   joystick_a[winIdx] = a ;
350   joystick_b[winIdx] = b ;
351   joystick_c[winIdx] = c ;
352   joystick_d[winIdx] = d ;
353   joystick_seq[winIdx] = sequence_number ;
354   glutPostRedisplay () ;
355 }
356
357 static void 
358 Mouse(int button, int updown, int x, int y)
359 {
360   int winIdx;
361   int window = getWindowAndIdx(&winIdx);
362   printf ( "%6d Window %d Mouse Click Callback:  %d %d %d %d\n",
363             ++sequence_number, window, button, updown, x, y ) ;
364   mouse_called[winIdx] = 1 ;
365   mouse_button[winIdx] = button ;
366   mouse_updown[winIdx] = updown ;
367   mouse_x[winIdx] = x ;
368   mouse_y[winIdx] = y ;
369   mouse_seq[winIdx] = sequence_number ;
370   mouse_mod[winIdx] = glutGetModifiers() ;
371   glutPostRedisplay () ;
372 }
373
374 static void 
375 MouseWheel(int wheel_number, int direction, int x, int y)
376 {
377   int winIdx;
378   int window = getWindowAndIdx(&winIdx);
379   printf ( "%6d Window %d Mouse Wheel Callback:  %d %d %d %d\n",
380             ++sequence_number, window, wheel_number, direction, x, y ) ;
381   mousewheel_called[winIdx] = 1 ;
382   mousewheel_number[winIdx] = wheel_number ;
383   mousewheel_direction[winIdx] = direction ;
384   mousewheel_x[winIdx] = x ;
385   mousewheel_y[winIdx] = y ;
386   mousewheel_seq[winIdx] = sequence_number ;
387   mousewheel_mod[winIdx] = glutGetModifiers() ;
388   glutPostRedisplay () ;
389 }
390
391 static void 
392 Motion(int x, int y)
393 {
394   int winIdx;
395   int window = getWindowAndIdx(&winIdx);
396   printf ( "%6d Window %d Mouse Motion Callback:  %d %d\n",
397             ++sequence_number, window, x, y ) ;
398   motion_called[winIdx] = 1 ;
399   motion_x[winIdx] = x ;
400   motion_y[winIdx] = y ;
401   motion_seq[winIdx] = sequence_number ;
402   motion_mod[winIdx] = glutGetModifiers() ;
403   glutPostRedisplay () ;
404 }
405
406 static void 
407 PassiveMotion(int x, int y)
408 {
409   int winIdx;
410   int window = getWindowAndIdx(&winIdx);
411   printf ( "%6d Window %d Mouse Passive Motion Callback:  %d %d\n",
412             ++sequence_number, window, x, y ) ;
413   passivemotion_called[winIdx] = 1 ;
414   passivemotion_x[winIdx] = x ;
415   passivemotion_y[winIdx] = y ;
416   passivemotion_seq[winIdx] = sequence_number ;
417   passivemotion_mod[winIdx] = glutGetModifiers() ;
418   glutPostRedisplay () ;
419 }
420
421 static void 
422 Entry(int state)
423 {
424   int winIdx;
425   int window = getWindowAndIdx(&winIdx);
426   printf ( "%6d Window %d Entry Callback:  %d\n",
427             ++sequence_number, window, state ) ;
428   entry_called[winIdx] = 1 ;
429   entry_seq[winIdx] = sequence_number;
430   entry_state[winIdx] = state;
431   glutPostRedisplay () ;
432 }
433
434 static void 
435 Close(void)
436 {
437   int window = getWindowAndIdx(NULL);
438   printf ( "%6d Window %d Close Callback\n",
439             ++sequence_number, window ) ;
440 }
441
442 static void 
443 OverlayDisplay(void)
444 {
445   int window = getWindowAndIdx(NULL);
446   printf ( "%6d Window %d OverlayDisplay Callback\n",
447             ++sequence_number, window ) ;
448   glutPostRedisplay () ;
449 }
450
451 static void 
452 WindowStatus(int state)
453 {
454   int window = getWindowAndIdx(NULL);
455   printf ( "%6d Window %d WindowStatus Callback:  %d\n",
456             ++sequence_number, window, state ) ;
457   glutPostRedisplay () ;
458 }
459
460 static void 
461 SpaceMotion(int x, int y, int z)
462 {
463   int window = getWindowAndIdx(NULL);
464   printf ( "%6d Window %d SpaceMotion Callback:  %d %d %d\n",
465             ++sequence_number, window, x, y, z ) ;
466   glutPostRedisplay () ;
467 }
468
469 static void 
470 SpaceRotation(int x, int y, int z)
471 {
472   int window = getWindowAndIdx(NULL);
473   printf ( "%6d Window %d SpaceRotation Callback:  %d %d %d\n",
474             ++sequence_number, window, x, y, z ) ;
475   glutPostRedisplay () ;
476 }
477
478 static void 
479 SpaceButton(int button, int updown)
480 {
481   int window = getWindowAndIdx(NULL);
482   printf ( "%6d Window %d SpaceButton Callback:  %d %d\n",
483             ++sequence_number, window, button, updown ) ;
484   glutPostRedisplay () ;
485 }
486
487 static void 
488 Dials(int x, int y)
489 {
490   int window = getWindowAndIdx(NULL);
491   printf ( "%6d Window %d Dials Callback:  %d %d\n",
492             ++sequence_number, window, x, y ) ;
493   glutPostRedisplay () ;
494 }
495
496 static void 
497 ButtonBox(int button, int updown)
498 {
499   int window = getWindowAndIdx(NULL);
500   printf ( "%6d Window %d ButtonBox Callback:  %d %d\n",
501             ++sequence_number, window, button, updown ) ;
502   glutPostRedisplay () ;
503 }
504
505 static void 
506 TabletMotion(int x, int y)
507 {
508   int window = getWindowAndIdx(NULL);
509   printf ( "%6d Window %d TabletMotion Callback:  %d %d\n",
510             ++sequence_number, window, x, y ) ;
511   glutPostRedisplay () ;
512 }
513
514 static void 
515 TabletButton(int button, int updown, int x, int y)
516 {
517   int window = getWindowAndIdx(NULL);
518   printf ( "%6d Window %d TabletButton Callback:  %d %d %d %d\n",
519             ++sequence_number, window, button, updown, x, y ) ;
520   glutPostRedisplay () ;
521 }
522
523 static void
524 MenuCallback ( int value )
525 {
526   int menu = glutGetMenu();
527   int window = getWindowAndIdx(NULL);
528   printf( "%6d Menu %d MenuCallback for menu opened in Window %d - value is %d\n",
529           ++sequence_number, menu, window, value );
530 }
531
532 static void 
533 MenuDestroy( void )
534 {
535   int menu = glutGetMenu();
536   menudestroy_called = 1 ;
537   printf ( "%6d Menu %d MenuDestroy Callback\n",
538             ++sequence_number, menu ) ;
539 }
540
541 static void 
542 MenuStatus( int status, int x, int y )
543 {
544   /* Menu and window for which this event is triggered are current when the callback is called */
545   int menu = glutGetMenu();
546   int window = getWindowAndIdx(NULL);
547   menustatus_called = 1 ;
548   printf ( "%6d Menu %d MenuStatus Callback in Window %d:  %d %d %d\n",
549             ++sequence_number, menu, window, status, x, y ) ;
550   glutPostRedisplay () ;
551 }
552
553
554 static void 
555 MenuState( int status )
556 {
557   /* Menu and window for which this event is triggered are current when the callback is called */
558   int menu = glutGetMenu();
559   int window = getWindowAndIdx(NULL);
560   menustate_called = 1 ;
561   printf ( "%6d Menu %d MenuState Callback in Window %d:  %d\n",
562             ++sequence_number, menu, window, status) ;
563   glutPostRedisplay () ;
564 }
565
566 static void Idle ( void )
567 {
568   ++sequence_number ;
569 }
570
571 static void SetWindowCallbacks( int first )
572 {
573     /* All these callbacks are set for only the current window */
574     glutDisplayFunc( Display );
575     glutReshapeFunc( Reshape );
576     glutPositionFunc( Position );
577     glutKeyboardFunc( Key );
578     glutSpecialFunc( Special );
579     glutKeyboardUpFunc( KeyUp );
580     glutSpecialUpFunc( SpecialUp );
581     if (first)
582         glutJoystickFunc( Joystick, 100 );
583     glutMouseFunc ( Mouse ) ;
584     glutMouseWheelFunc ( MouseWheel ) ;
585     glutMotionFunc ( Motion ) ;
586     glutPassiveMotionFunc ( PassiveMotion ) ;
587     glutEntryFunc ( Entry ) ;
588     glutCloseFunc ( Close ) ;
589     glutOverlayDisplayFunc ( OverlayDisplay ) ;
590     glutSpaceballMotionFunc ( SpaceMotion ) ;
591     glutSpaceballRotateFunc ( SpaceRotation ) ;
592     glutSpaceballButtonFunc ( SpaceButton ) ;
593     glutButtonBoxFunc ( ButtonBox ) ;
594     glutDialsFunc ( Dials ) ;
595     glutTabletMotionFunc ( TabletMotion ) ;
596     glutTabletButtonFunc ( TabletButton ) ;
597     /* glutVisibilityFunc is deprecated in favor of glutWindowStatusFunc, which provides more detail.
598      * Setting one of these overwrites the other (see docs).
599      */
600     glutVisibilityFunc ( Visibility );  /* This will thus never be called, as glutWindowStatusFunc is set afterwards */
601     glutWindowStatusFunc ( WindowStatus ) ;
602 }
603
604 int 
605 main(int argc, char *argv[])
606 {
607   char dummy_string[STRING_LENGTH];
608
609   int menuID, subMenuA, subMenuB;
610
611   glutInitWarningFunc(Warning);
612   glutInitErrorFunc(Error);
613   glutInitWindowSize(500, 250);
614   glutInitWindowPosition ( 140, 140 );
615   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE );
616   glutInit(&argc, argv);
617   /* global setting: mainloop does not return when a window is closed, only returns when all windows are closed */
618   glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_CONTINUE_EXECUTION);
619   /* global setting: repeated keys generating by keeping the key pressed down are passed on to the keyboard callback */
620   /* There are two functions to control this behavior, glutSetKeyRepeat to set it globally, and glutIgnoreKeyRepeat to set it per window.
621    * These two interact however. If key repeat is globally switched off (glutSetKeyRepeat(GLUT_KEY_REPEAT_OFF)), it cannot be overridden
622    * (switched back on) for a specific window with glutIgnoreKeyRepeat. However, if key repeat is globally switched on
623    * (glutSetKeyRepeat(GLUT_KEY_REPEAT_ON)), it can be overridden (switched off) with glutIgnoreKeyRepeat on a per-window basis. That is
624    * what we demonstrate here.
625    */
626   glutSetKeyRepeat(GLUT_KEY_REPEAT_ON);
627
628   /* Set other global callback (global as in not associated with any specific menu or window) */
629   glutIdleFunc ( Idle );
630   glutMenuStatusFunc ( MenuStatus );
631   glutMenuStateFunc  ( MenuState ); /* Note that glutMenuStatusFunc is an enhanced version of the deprecated glutMenuStateFunc. */
632
633
634   /* Open first window */
635   windows[0] = glutCreateWindow( "Callback Demo" );
636   printf ( "Creating window %d as 'Callback Demo'\n", windows[0] ) ;
637
638   glClearColor(1.0, 1.0, 1.0, 1.0);
639
640   /* callbacks, settings and menus for this window */
641   SetWindowCallbacks( 1 );
642   glutIgnoreKeyRepeat(GL_TRUE);
643
644   subMenuA = glutCreateMenu( MenuCallback );
645   glutAddMenuEntry( "Sub menu A1 (01)", 11 );
646   glutAddMenuEntry( "Sub menu A2 (02)", 12 );
647   glutAddMenuEntry( "Sub menu A3 (03)", 13 );
648   glutMenuDestroyFunc ( MenuDestroy );  /* callback specific to this menu */
649
650   subMenuB = glutCreateMenu( MenuCallback );
651   glutAddMenuEntry( "Sub menu B1 (04)", 14 );
652   glutAddMenuEntry( "Sub menu B2 (05)", 15 );
653   glutAddMenuEntry( "Sub menu B3 (06)", 16 );
654   glutAddSubMenu( "Going to sub menu A", subMenuA );
655   glutMenuDestroyFunc ( MenuDestroy );  /* callback specific to this menu */
656
657   menuID = glutCreateMenu( MenuCallback );
658   glutAddMenuEntry( "Entry one",   21 );
659   glutAddMenuEntry( "Entry two",   22 );
660   glutAddMenuEntry( "Entry three", 23 );
661   glutAddMenuEntry( "Entry four",  24 );
662   glutAddMenuEntry( "Entry five",  25 );
663   glutAddSubMenu( "Enter sub menu A", subMenuA );
664   glutAddSubMenu( "Enter sub menu B", subMenuB );
665   glutMenuDestroyFunc ( MenuDestroy );  /* callback specific to this menu */
666
667   glutAttachMenu( GLUT_LEFT_BUTTON );
668
669
670   /* Position second window right next to the first */
671   glutInitWindowPosition ( 140+500+2*glutGet(GLUT_WINDOW_BORDER_WIDTH), 140 );
672   glutInitWindowSize(600, 600);
673   windows[1] = glutCreateWindow( "Second Window" );
674   printf ( "Creating window %d as 'Second Window'\n", windows[1] ) ;
675
676   glClearColor(1.0, 1.0, 1.0, 1.0);
677
678   /* callbacks, settings and menus for this window */
679   SetWindowCallbacks( 0 );
680   glutIgnoreKeyRepeat(GL_TRUE);
681
682   glutSetMenu(subMenuB);
683   glutAttachMenu( GLUT_RIGHT_BUTTON );
684
685
686   /* position a third window as a subwindow of the second */
687   windows[2] = glutCreateSubWindow(windows[1],0,300,600,300);
688   printf ( "Creating window %d as subwindow to 'Second Window'\n", windows[2] ) ;
689
690   glClearColor(0.7f, 0.7f, 0.7f, 1.0);
691
692   /* callbacks, settings and menus for this window */
693   SetWindowCallbacks( 0 );
694   glutSetCursor(GLUT_CURSOR_CROSSHAIR); /* Cursors are per window */
695
696   glutSetMenu(subMenuA);
697   glutAttachMenu( GLUT_RIGHT_BUTTON );
698
699
700   /* position a fourth window as a subsubwindow (grandchild) of the second */
701   windows[3] = glutCreateSubWindow(windows[2],300,0,300,300);
702   printf ( "Creating window %d as subsubwindow to 'Second Window'\n", windows[3] ) ;
703
704   glClearColor(0.4f, 0.4f, 0.4f, 1.0);
705
706   /* callbacks and menus for this window */
707   SetWindowCallbacks( 0 );
708   glutSetCursor(GLUT_CURSOR_INHERIT);   /* Inherit cursor look from parent (this is default on window creation) - comment the below to see in action */
709   glutSetCursor(GLUT_CURSOR_CYCLE);
710
711
712   printf ( "Please enter something to continue: " );
713   fgets ( dummy_string, STRING_LENGTH, stdin );
714
715   glutMainLoop();
716
717   printf ( "Back from the 'freeglut' main loop\n" ) ;
718
719   return EXIT_SUCCESS;
720 }