5 To get started with mixed model programming with Motif and OpenGL, this
6 boilerplate `application' might help get you started.
8 This program honors two environment variables:
10 SETVISUAL <id> Makes the application use the indicated visual,
11 instead of the one chosen by glxChooseVisual.
13 SAMEVISUAL Make the application use the same visual for the
14 GUI as for the 3D GL Widget.
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.
20 If you have suggestions for improvements, please mail to:
23 Jeroen van der Zijp <jvz@cyberia.cfdrc.com>
26 Feel free to turn this into a useful program!!
33 This code is hereby placed under GNU GENERAL PUBLIC LICENSE.
34 Copyright (C) 1996 Jeroen van der Zijp <jvz@cyberia.cfdrc.com>
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.
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.
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.
52 /* Include the kitchen sink */
55 #include <X11/Intrinsic.h>
56 #include <X11/StringDefs.h>
57 #include <X11/cursorfont.h>
58 #include <X11/keysym.h>
61 #include <Xm/RowColumn.h>
63 #include <Xm/CascadeB.h>
64 #include <Xm/BulletinB.h>
65 #include <Xm/DialogS.h>
67 #include <Xm/MessageB.h>
69 #include <Xm/Separator.h>
70 #include <Xm/MwmUtil.h>
72 /* Now some good stuff */
73 #include <GLwMDrawA.h>
82 Colormap gui_colormap
;
84 XVisualInfo
*gl_visualinfo
;
85 XtAppContext app_context
;
94 GLXContext glx_context
;
100 /* Requested attributes; fix as you see fit */
101 static int glxConfig
[]={
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
);
123 /* Sample application */
124 int main(int argc
, char *argv
[]){
127 int nvisinfos
,visid
,n
;
129 Widget pane
,cascade
,but
;
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!!!
136 XtToolkitInitialize();
138 /* Make application context */
139 app_context
=XtCreateApplicationContext();
141 /* Try open display */
142 display
=XtOpenDisplay(app_context
,NULL
,"boilerPlate","BoilerPlate",NULL
,0,&argc
,argv
);
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");
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");
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);
163 /* User insists on a specific visual */
164 if((thevisual
=getenv("SETVISUAL"))!=NULL
){
165 if(sscanf(thevisual
,"%x",&visid
)==1){
167 gl_visualinfo
=XGetVisualInfo(display
,VisualIDMask
,&vi
,&nvisinfos
);
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");
176 /* Find visual the regular way */
178 gl_visualinfo
=glXChooseVisual(display
,DefaultScreen(display
),glxConfig
);
181 /* Make sure we have a visual */
183 fprintf(stderr
,"Unable to obtain visual for graphics\n");
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
));
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
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
,
210 fprintf(stderr
,"Unable to create private colormap\n");
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.
221 if(getenv("SAMEVISUAL")!=NULL
){
222 gui_visual
=gl_visualinfo
->visual
;
223 gui_colormap
=gl_colormap
;
226 fprintf(stderr
,"GUI uses visual: %lx\n",XVisualIDFromVisual(gui_visual
));
228 /* Create application shell, finally */
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
);
238 mainwindow
=XmCreateMainWindow(toplevel
,"window",args
,n
);
239 XtManageChild(mainwindow
);
243 XtSetArg(args
[n
],XmNmarginWidth
,0); n
++;
244 XtSetArg(args
[n
],XmNmarginHeight
,0); n
++;
245 menubar
=XmCreateMenuBar(mainwindow
,"menubar",args
,2);
246 XtManageChild(menubar
);
249 pane
=XmCreatePulldownMenu(menubar
,"pane",args
,n
);
251 but
=XmCreatePushButton(pane
,"Open",args
,n
);
253 but
=XmCreatePushButton(pane
,"Save",args
,n
);
255 but
=XmCreatePushButton(pane
,"Save As",args
,n
);
257 but
=XmCreatePushButton(pane
,"Quit",args
,n
);
258 XtAddCallback(but
,XmNactivateCallback
,byeCB
,(XtPointer
)NULL
);
260 XtSetArg(args
[0],XmNsubMenuId
,pane
);
261 cascade
=XmCreateCascadeButton(menubar
,"File",args
,1);
262 XtManageChild(cascade
);
265 pane
=XmCreatePulldownMenu(menubar
,"pane",args
,n
);
267 but
=XmCreatePushButton(pane
,"About",args
,n
);
268 XtAddCallback(but
,XmNactivateCallback
,aboutCB
,(XtPointer
)NULL
);
270 XtSetArg(args
[0],XmNsubMenuId
,pane
);
271 cascade
=XmCreateCascadeButton(menubar
,"Help",args
,1);
272 XtManageChild(cascade
);
273 XtVaSetValues(menubar
,XmNmenuHelpWidget
,cascade
,NULL
);
275 /* Main window form */
277 XtSetArg(args
[n
],XmNmarginWidth
,5); n
++;
278 XtSetArg(args
[n
],XmNmarginHeight
,5); n
++;
279 mainform
=XmCreateForm(mainwindow
,"mainForm",args
,n
);
280 XtManageChild(mainform
);
282 /* Some nice button */
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
);
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
);
299 /* Main window frame */
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
);
310 /* GL drawing area */
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
);
325 /* Set into main window */
326 XmMainWindowSetAreas(mainwindow
,menubar
,NULL
,NULL
,NULL
,mainform
);
327 XtRealizeWidget(toplevel
);
329 /* Loop until were done */
330 XtAppMainLoop(app_context
);
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";
347 static void exposeCB(Widget w
,XtPointer client_data
,GLwDrawingAreaCallbackStruct
*cbs
){
348 GLwDrawingAreaMakeCurrent(glwidget
,glx_context
);
350 glClear(GL_DEPTH_BUFFER_BIT
|GL_COLOR_BUFFER_BIT
);
351 glMatrixMode(GL_PROJECTION
);
354 glOrtho(-1.0,1.0,-1.0,1.0,0.0,1.0);
356 glMatrixMode(GL_MODELVIEW
);
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);
365 glXSwapBuffers(display
,XtWindow(glwidget
));
369 /* Initialize widget */
370 static void initCB(Widget w
,XtPointer client_data
,GLwDrawingAreaCallbackStruct
*cbs
){
372 /* First, create context. We prefer direct rendering */
373 glx_context
=glXCreateContext(display
,gl_visualinfo
,0,TRUE
);
375 fprintf(stderr
,"Unable to create gl context\n");
379 /* Make it current */
380 GLwDrawingAreaMakeCurrent(glwidget
,glx_context
);
383 glViewport(0,0,cbs
->width
,cbs
->height
);
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);
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
);
404 /* Boilerplate event handling */
405 static void inputCB(Widget w
,XtPointer client_data
,GLwDrawingAreaCallbackStruct
*cbs
){
406 switch(cbs
->event
->type
){
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;
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;
422 fprintf(stderr
,"Moved mouse to (%d %d)\n",
423 cbs
->event
->xbutton
.x
,
424 cbs
->event
->xbutton
.y
);
430 /* Hasta la vista, baby */
431 static void byeCB(Widget w
,XtPointer client_data
,XtPointer call_data
){
436 /* Pop informative panel */
437 static void aboutCB(Widget w
,XtPointer client_data
,XtPointer call_data
){
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);
448 XtUnmanageChild(XmMessageBoxGetChild(box
,XmDIALOG_HELP_BUTTON
));
449 XtUnmanageChild(XmMessageBoxGetChild(box
,XmDIALOG_CANCEL_BUTTON
));