bug fixes, added missing state query cases
[mesa.git] / src / glw / boilerplate.c
1 /*
2
3 BOILERPLATE
4
5 To get started with mixed model programming with Motif and OpenGL, this
6 boilerplate `application' might help get you started.
7
8 This program honors two environment variables:
9
10 SETVISUAL <id> Makes the application use the indicated visual,
11 instead of the one chosen by glxChooseVisual.
12
13 SAMEVISUAL Make the application use the same visual for the
14 GUI as for the 3D GL Widget.
15
16 The basic idea is to minimize colormap `flash' on systems with only one
17 hardware colormap, especially when focus shifts between several
18 of the application's windows, e.g. the about box.
19
20 If you have suggestions for improvements, please mail to:
21
22
23 Jeroen van der Zijp <jvz@cyberia.cfdrc.com>
24
25
26 Feel free to turn this into a useful program!!
27
28 */
29
30
31 /*
32
33 This code is hereby placed under GNU GENERAL PUBLIC LICENSE.
34 Copyright (C) 1996 Jeroen van der Zijp <jvz@cyberia.cfdrc.com>
35
36 This program is free software; you can redistribute it and/or modify
37 it under the terms of the GNU General Public License as published by
38 the Free Software Foundation; either version 2 of the License, or
39 (at your option) any later version.
40
41 This program is distributed in the hope that it will be useful,
42 but WITHOUT ANY WARRANTY; without even the implied warranty of
43 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 GNU General Public License for more details.
45
46 You should have received a copy of the GNU General Public License
47 along with this program; if not, write to the Free Software
48 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
49 */
50
51
52 /* Include the kitchen sink */
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <X11/Intrinsic.h>
56 #include <X11/StringDefs.h>
57 #include <X11/cursorfont.h>
58 #include <X11/keysym.h>
59 #include <Xm/Xm.h>
60 #include <Xm/MainW.h>
61 #include <Xm/RowColumn.h>
62 #include <Xm/PushB.h>
63 #include <Xm/CascadeB.h>
64 #include <Xm/BulletinB.h>
65 #include <Xm/DialogS.h>
66 #include <Xm/Frame.h>
67 #include <Xm/MessageB.h>
68 #include <Xm/Form.h>
69 #include <Xm/Separator.h>
70 #include <Xm/MwmUtil.h>
71
72 /* Now some good stuff */
73 #include <GLwMDrawA.h>
74 #include <GL/gl.h>
75 #include <GL/glu.h>
76 #include <GL/glx.h>
77
78
79 /* Stuff */
80 Display *display;
81 Visual *gui_visual;
82 Colormap gui_colormap;
83 Colormap gl_colormap;
84 XVisualInfo *gl_visualinfo;
85 XtAppContext app_context;
86 Widget toplevel;
87 Widget mainwindow;
88 Widget menubar;
89 Widget mainform;
90 Widget mainframe;
91 Widget glwidget;
92 Widget button;
93 Widget separator;
94 GLXContext glx_context;
95
96 #ifndef __cplusplus
97 #define c_class class
98 #endif
99
100 /* Requested attributes; fix as you see fit */
101 static int glxConfig[]={
102 GLX_RGBA,
103 GLX_DOUBLEBUFFER,
104 GLX_DEPTH_SIZE, 16,
105 GLX_RED_SIZE, 1,
106 GLX_GREEN_SIZE, 1,
107 GLX_BLUE_SIZE, 1,
108 None
109 };
110
111
112 /* Forwards */
113 static void exposeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs);
114 static void initCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs);
115 static void resizeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs);
116 static void inputCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs);
117 static void byeCB(Widget w,XtPointer client_data,XtPointer call_data);
118 static void aboutCB(Widget w,XtPointer client_data,XtPointer call_data);
119 static char* showvisualclass(int cls);
120
121
122
123 /* Sample application */
124 int main(int argc, char *argv[]){
125 char *thevisual;
126 XVisualInfo vi;
127 int nvisinfos,visid,n;
128 Arg args[30];
129 Widget pane,cascade,but;
130
131 /*
132 ** Initialize toolkit
133 ** We do *not* use XtAppInitialize as we want to figure visual and
134 ** colormap BEFORE we create the top level shell!!!
135 */
136 XtToolkitInitialize();
137
138 /* Make application context */
139 app_context=XtCreateApplicationContext();
140
141 /* Try open display */
142 display=XtOpenDisplay(app_context,NULL,"boilerPlate","BoilerPlate",NULL,0,&argc,argv);
143
144 /* Report failure */
145 if(!display){
146 fprintf(stderr,"Unable to open the specified display.\n");
147 fprintf(stderr,"Set your `DISPLAY' environment variable properly or\n");
148 fprintf(stderr,"use the `xhost' command to authorize access to the display.\n");
149 exit(1);
150 }
151
152 /* Check for extension; for Mesa, this is always cool */
153 if(!glXQueryExtension(display,NULL,NULL)){
154 fprintf(stderr,"The specified display does not support the OpenGL extension\n");
155 exit(1);
156 }
157
158 /* Init with default visual and colormap */
159 gui_visual=DefaultVisual(display,0);
160 gui_colormap=DefaultColormap(display,0);
161 gl_colormap=DefaultColormap(display,0);
162
163 /* User insists on a specific visual */
164 if((thevisual=getenv("SETVISUAL"))!=NULL){
165 if(sscanf(thevisual,"%x",&visid)==1){
166 vi.visualid=visid;
167 gl_visualinfo=XGetVisualInfo(display,VisualIDMask,&vi,&nvisinfos);
168 }
169 else{
170 fprintf(stderr,"Please set the `SETVISUAL' variable in hexadecimal\n");
171 fprintf(stderr,"Use one of the Visual ID's reported by `xdpyinfo'\n");
172 exit(1);
173 }
174 }
175
176 /* Find visual the regular way */
177 else{
178 gl_visualinfo=glXChooseVisual(display,DefaultScreen(display),glxConfig);
179 }
180
181 /* Make sure we have a visual */
182 if(!gl_visualinfo){
183 fprintf(stderr,"Unable to obtain visual for graphics\n");
184 exit(1);
185 }
186
187 /* Show what visual is being used */
188 fprintf(stderr,"Using the following visual:\n");
189 fprintf(stderr," visualid: %lx\n",gl_visualinfo->visualid);
190 fprintf(stderr," depth: %d\n",gl_visualinfo->depth);
191 fprintf(stderr," screen: %d\n",gl_visualinfo->screen);
192 fprintf(stderr," bits/rgb: %d\n",gl_visualinfo->bits_per_rgb);
193 fprintf(stderr," class: %s\n",showvisualclass(gl_visualinfo->c_class));
194
195 /*
196 ** If not using default visual, we need a colormap for this visual.
197 ** Yes, the GL widget can allocate one itself, but we want to make
198 ** sure the GUI and the 3D have the same one (if hardware does not
199 ** allow more than one simultaneously).
200 ** This prevents nasty flashing when the window with the 3D widget
201 ** looses the focus.
202 */
203 if(gl_visualinfo->visual!=DefaultVisual(display,0)){
204 fprintf(stderr,"Making another colormap\n");
205 gl_colormap=XCreateColormap(display,
206 RootWindow(display,0),
207 gl_visualinfo->visual,
208 AllocNone);
209 if(!gl_colormap){
210 fprintf(stderr,"Unable to create private colormap\n");
211 exit(1);
212 }
213 }
214
215 /*
216 ** Use common visual for GUI and GL?
217 ** Maybe you can invoke some hardware interrogation function and
218 ** see if more than one hardware map is supported. For the purpose
219 ** of this demo, we'll use an environment variable instead.
220 */
221 if(getenv("SAMEVISUAL")!=NULL){
222 gui_visual=gl_visualinfo->visual;
223 gui_colormap=gl_colormap;
224 }
225
226 fprintf(stderr,"GUI uses visual: %lx\n",XVisualIDFromVisual(gui_visual));
227
228 /* Create application shell, finally */
229 n=0;
230 XtSetArg(args[n],XmNvisual,gui_visual); n++; /* Plug in that visual */
231 XtSetArg(args[n],XmNcolormap,gui_colormap); n++; /* And that colormap */
232 toplevel=XtAppCreateShell("boilerPlate","BoilerPlate",
233 applicationShellWidgetClass,display,args,n);
234
235
236 /* Main window */
237 n=0;
238 mainwindow=XmCreateMainWindow(toplevel,"window",args,n);
239 XtManageChild(mainwindow);
240
241 /* Make a menu */
242 n=0;
243 XtSetArg(args[n],XmNmarginWidth,0); n++;
244 XtSetArg(args[n],XmNmarginHeight,0); n++;
245 menubar=XmCreateMenuBar(mainwindow,"menubar",args,2);
246 XtManageChild(menubar);
247
248 n=0;
249 pane=XmCreatePulldownMenu(menubar,"pane",args,n);
250 n=0;
251 but=XmCreatePushButton(pane,"Open",args,n);
252 XtManageChild(but);
253 but=XmCreatePushButton(pane,"Save",args,n);
254 XtManageChild(but);
255 but=XmCreatePushButton(pane,"Save As",args,n);
256 XtManageChild(but);
257 but=XmCreatePushButton(pane,"Quit",args,n);
258 XtAddCallback(but,XmNactivateCallback,byeCB,(XtPointer)NULL);
259 XtManageChild(but);
260 XtSetArg(args[0],XmNsubMenuId,pane);
261 cascade=XmCreateCascadeButton(menubar,"File",args,1);
262 XtManageChild(cascade);
263
264 n=0;
265 pane=XmCreatePulldownMenu(menubar,"pane",args,n);
266 n=0;
267 but=XmCreatePushButton(pane,"About",args,n);
268 XtAddCallback(but,XmNactivateCallback,aboutCB,(XtPointer)NULL);
269 XtManageChild(but);
270 XtSetArg(args[0],XmNsubMenuId,pane);
271 cascade=XmCreateCascadeButton(menubar,"Help",args,1);
272 XtManageChild(cascade);
273 XtVaSetValues(menubar,XmNmenuHelpWidget,cascade,NULL);
274
275 /* Main window form */
276 n=0;
277 XtSetArg(args[n],XmNmarginWidth,5); n++;
278 XtSetArg(args[n],XmNmarginHeight,5); n++;
279 mainform=XmCreateForm(mainwindow,"mainForm",args,n);
280 XtManageChild(mainform);
281
282 /* Some nice button */
283 n=0;
284 XtSetArg(args[n],XmNbottomAttachment,XmATTACH_FORM); n++;
285 XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
286 button=XmCreatePushButton(mainform,"Bye",args,n);
287 XtAddCallback(button,XmNactivateCallback,byeCB,(XtPointer)NULL);
288 XtManageChild(button);
289
290 n=0;
291 XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
292 XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
293 XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
294 XtSetArg(args[n],XmNbottomWidget,button); n++;
295 XtSetArg(args[n],XmNshadowType,XmSHADOW_ETCHED_IN); n++;
296 separator=XmCreateSeparator(mainform,"separator",args,n);
297 XtManageChild(separator);
298
299 /* Main window frame */
300 n = 0;
301 XtSetArg(args[n],XmNleftAttachment,XmATTACH_FORM); n++;
302 XtSetArg(args[n],XmNrightAttachment,XmATTACH_FORM); n++;
303 XtSetArg(args[n],XmNtopAttachment,XmATTACH_FORM); n++;
304 XtSetArg(args[n],XmNbottomAttachment,XmATTACH_WIDGET); n++;
305 XtSetArg(args[n],XmNbottomWidget,separator); n++;
306 XtSetArg(args[n],XmNshadowType,XmSHADOW_IN); n++;
307 mainframe = XmCreateFrame(mainform,"mainFrame",args,n);
308 XtManageChild(mainframe);
309
310 /* GL drawing area */
311 n = 0;
312 XtSetArg(args[n],XmNcolormap,gl_colormap); n++;
313 XtSetArg(args[n],GLwNvisualInfo,gl_visualinfo); n++;
314 XtSetArg(args[n],GLwNinstallColormap,True); n++;
315 XtSetArg(args[n],XmNtraversalOn,True); n++;
316 XtSetArg(args[n],XmNwidth,400); n++;
317 XtSetArg(args[n],XmNheight,300); n++;
318 glwidget = GLwCreateMDrawingArea(mainframe,"glWidget",args,n);
319 XtAddCallback(glwidget,GLwNexposeCallback,(XtCallbackProc)exposeCB,(XtPointer)NULL);
320 XtAddCallback(glwidget,GLwNresizeCallback,(XtCallbackProc)resizeCB,(XtPointer)NULL);
321 XtAddCallback(glwidget,GLwNginitCallback,(XtCallbackProc)initCB,(XtPointer)NULL);
322 XtAddCallback(glwidget,GLwNinputCallback,(XtCallbackProc)inputCB,(XtPointer)NULL);
323 XtManageChild(glwidget);
324
325 /* Set into main window */
326 XmMainWindowSetAreas(mainwindow,menubar,NULL,NULL,NULL,mainform);
327 XtRealizeWidget(toplevel);
328
329 /* Loop until were done */
330 XtAppMainLoop(app_context);
331 return 0;
332 }
333
334
335 /* Show visual class */
336 static char* showvisualclass(int cls){
337 if(cls==TrueColor) return "TrueColor";
338 if(cls==DirectColor) return "DirectColor";
339 if(cls==PseudoColor) return "PseudoColor";
340 if(cls==StaticColor) return "StaticColor";
341 if(cls==GrayScale) return "GrayScale";
342 if(cls==StaticGray) return "StaticGray";
343 return "Unknown";
344 }
345
346
347 static void exposeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){
348 GLwDrawingAreaMakeCurrent(glwidget,glx_context);
349
350 glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
351 glMatrixMode(GL_PROJECTION);
352
353 glLoadIdentity();
354 glOrtho(-1.0,1.0,-1.0,1.0,0.0,1.0);
355
356 glMatrixMode(GL_MODELVIEW);
357
358 glLoadIdentity();
359
360 glColor3f(1.0,0.0,0.0);
361 glBegin(GL_LINE_STRIP);
362 glVertex3f(-1.0,-1.0,0.0);
363 glVertex3f( 1.0, 1.0,0.0);
364 glEnd();
365 glXSwapBuffers(display,XtWindow(glwidget));
366 }
367
368
369 /* Initialize widget */
370 static void initCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){
371
372 /* First, create context. We prefer direct rendering */
373 glx_context=glXCreateContext(display,gl_visualinfo,0,TRUE);
374 if(!glx_context){
375 fprintf(stderr,"Unable to create gl context\n");
376 exit(1);
377 }
378
379 /* Make it current */
380 GLwDrawingAreaMakeCurrent(glwidget,glx_context);
381
382 /* Set a viewport */
383 glViewport(0,0,cbs->width,cbs->height);
384
385 /* You might want to do a lot more here ... */
386 glEnable(GL_DEPTH_TEST);
387 glDepthFunc(GL_LEQUAL);
388 glClearColor(1.0,1.0,1.0,1.0);
389 glClearDepth(1.0);
390
391
392 }
393
394
395 /* Widget changed size, so adjust txform */
396 static void resizeCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){
397 GLwDrawingAreaMakeCurrent(glwidget,glx_context);
398 glViewport(0,0,cbs->width,cbs->height);
399
400 /* blablabla */
401 }
402
403
404 /* Boilerplate event handling */
405 static void inputCB(Widget w,XtPointer client_data,GLwDrawingAreaCallbackStruct *cbs){
406 switch(cbs->event->type){
407 case ButtonPress:
408 switch(cbs->event->xbutton.button){
409 case Button1: fprintf(stderr,"Pressed 1\n"); break;
410 case Button2: fprintf(stderr,"Pressed 2\n"); break;
411 case Button3: fprintf(stderr,"Pressed 3\n"); break;
412 }
413 break;
414 case ButtonRelease:
415 switch(cbs->event->xbutton.button){
416 case Button1: fprintf(stderr,"Released 1\n"); break;
417 case Button2: fprintf(stderr,"Released 2\n"); break;
418 case Button3: fprintf(stderr,"Released 3\n"); break;
419 }
420 break;
421 case MotionNotify:
422 fprintf(stderr,"Moved mouse to (%d %d)\n",
423 cbs->event->xbutton.x,
424 cbs->event->xbutton.y);
425 break;
426 }
427 }
428
429
430 /* Hasta la vista, baby */
431 static void byeCB(Widget w,XtPointer client_data,XtPointer call_data){
432 exit(0);
433 }
434
435
436 /* Pop informative panel */
437 static void aboutCB(Widget w,XtPointer client_data,XtPointer call_data){
438 Arg args[10];
439 XmString str;
440 Widget box;
441 str=XmStringCreateLtoR("Boilerplate Mixed Model Programming Example\n\n (C) 1996 Jeroen van der Zijp \n\n jvz@cyberia.cfdrc.com",XmSTRING_DEFAULT_CHARSET);
442 XtSetArg(args[0],XmNnoResize,True);
443 XtSetArg(args[1],XmNautoUnmanage,True);
444 XtSetArg(args[2],XmNmessageString,str);
445 XtSetArg(args[3],XmNdefaultPosition,False);
446 box=XmCreateInformationDialog(toplevel,"About Boilerplate",args,4);
447 XtManageChild(box);
448 XtUnmanageChild(XmMessageBoxGetChild(box,XmDIALOG_HELP_BUTTON));
449 XtUnmanageChild(XmMessageBoxGetChild(box,XmDIALOG_CANCEL_BUTTON));
450 XmStringFree(str);
451 }