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