Warning, /include/Geant4/toolx/Xt/OpenGLArea is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef toolx_Xt_OpenGLArea
0005 #define toolx_Xt_OpenGLArea
0006
0007 #include <X11/IntrinsicP.h>
0008 #include <X11/CoreP.h>
0009 #include <X11/CompositeP.h>
0010 #include <X11/StringDefs.h>
0011
0012 #ifndef GL_GLEXT_LEGACY
0013 #define GL_GLEXT_LEGACY
0014 #endif
0015 #include <GL/gl.h>
0016
0017 #ifndef GL_GLEXT_PROTOTYPES
0018 #define GL_GLEXT_PROTOTYPES
0019 #endif
0020 #include <GL/glext.h>
0021
0022 #include <GL/glx.h>
0023
0024 #include <stdio.h>
0025 #include <stdlib.h>
0026 #include <stdarg.h>
0027
0028 namespace toolx {
0029 namespace Xt {
0030
0031 ///////////////////////////////////////////////////////////
0032 ///////////////////////////////////////////////////////////
0033 ///////////////////////////////////////////////////////////
0034
0035 typedef struct _OpenGLAreaClassRec* OpenGLAreaWidgetClass;
0036 typedef struct _OpenGLAreaRec* OpenGLAreaWidget;
0037
0038 typedef struct {
0039 int reason;
0040 XEvent* event;
0041 } XoAnyCallbackStruct;
0042
0043 #define XoCR_PAINT 1
0044 #define XoCR_EVENT 2
0045
0046 #define XoNdoubleBufferOn toolx::Xt::OpenGLArea::XoN_doubleBufferOn()
0047 #define XoNpaintCallback toolx::Xt::OpenGLArea::XoN_paintCallback()
0048 #define XoNeventCallback toolx::Xt::OpenGLArea::XoN_eventCallback()
0049
0050 ///////////////////////////////////////////////////////////
0051 ///////////////////////////////////////////////////////////
0052 ///////////////////////////////////////////////////////////
0053
0054 typedef struct {
0055 void* extension;
0056 } OpenGLAreaClassPart;
0057
0058 typedef struct _OpenGLAreaClassRec {
0059 CoreClassPart core_class;
0060 CompositeClassPart composite_class;
0061 OpenGLAreaClassPart openGLArea_class;
0062 } OpenGLAreaClassRec;
0063
0064 typedef struct {
0065 Boolean doubleBufferOn;
0066 XtCallbackList paintCallback;
0067 XtCallbackList eventCallback;
0068 Visual* visual;
0069 Boolean installColormap;
0070 GLXContext glContext;
0071 } OpenGLAreaPart;
0072
0073 typedef struct _OpenGLAreaRec {
0074 CorePart core;
0075 CompositePart composite;
0076 OpenGLAreaPart openGLArea;
0077 } OpenGLAreaRec;
0078
0079 ///////////////////////////////////////////////////////////
0080 ///////////////////////////////////////////////////////////
0081 ///////////////////////////////////////////////////////////
0082
0083 class OpenGLArea {
0084 protected:
0085 static const char* class_name() {static const char* s_s = "OpenGLArea";return s_s;}
0086 static const char* XoC_DoubleBufferOn() {static const char* s_s = "DoubleBufferOn";return s_s;}
0087 public:
0088 static const char* XoN_doubleBufferOn() {static const char* s_s = "doubleBufferOn";return s_s;}
0089 static const char* XoN_paintCallback() {static const char* s_s = "paintCallback";return s_s;}
0090 static const char* XoN_eventCallback() {static const char* s_s = "eventCallback";return s_s;}
0091 public:
0092 static void paint(Widget a_this) {
0093 if(!XtIsRealized(a_this)) return;
0094 if(make_current(a_this)==1) {
0095 XoAnyCallbackStruct value;
0096 value.reason = XoCR_PAINT;
0097 value.event = 0;
0098 ::XtCallCallbacks(a_this,XoNpaintCallback,(XtPointer)&value);
0099 ::glXSwapBuffers(XtDisplay(a_this),XtWindow(a_this));
0100 ::glXMakeCurrent(XtDisplay(a_this),None,NULL);
0101 }
0102 }
0103 protected:
0104 static void initialize_class(void) {}
0105
0106 static void initialize_widget(Widget a_request,Widget a_this,ArgList,Cardinal*) {
0107 if(a_request->core.width<=0) a_this->core.width = 100;
0108 if(a_request->core.height<=0) a_this->core.height = 100;
0109
0110 OpenGLAreaPart& athis = _athis(a_this);
0111 athis.visual = CopyFromParent;
0112 athis.installColormap = False;
0113 athis.glContext = NULL;
0114
0115 Display* display;
0116 Screen* screen;
0117 int iscreen;
0118 XVisualInfo* vinfo;
0119 display = XtDisplay(a_this);
0120 screen = XtScreen(a_this);
0121 iscreen = XScreenNumberOfScreen(screen);
0122
0123 {int error,event;
0124 if(::glXQueryExtension(display,&error,&event)==0) {
0125 CWarn ("X server does not have OpenGL extensions.\n");
0126 }}
0127
0128 if(athis.doubleBufferOn==True) {
0129 int atbs_1[] = {
0130 GLX_RGBA,
0131 GLX_RED_SIZE, 1,
0132 GLX_GREEN_SIZE, 1,
0133 GLX_BLUE_SIZE, 1,
0134 GLX_ALPHA_SIZE, 1,
0135 GLX_DEPTH_SIZE, 1,
0136 GLX_DOUBLEBUFFER,
0137 None
0138 };
0139 vinfo = ::glXChooseVisual (display,iscreen,atbs_1);
0140 if(vinfo==NULL) { //GLX_ALPHA_SIZE : problem with Xming. Try without it.
0141 int atbs_2[] = {
0142 GLX_RGBA,
0143 GLX_RED_SIZE, 1,
0144 GLX_GREEN_SIZE, 1,
0145 GLX_BLUE_SIZE, 1,
0146 GLX_DEPTH_SIZE, 1,
0147 GLX_DOUBLEBUFFER,
0148 None
0149 };
0150 vinfo = ::glXChooseVisual (display,iscreen,atbs_2);
0151 }
0152 } else {
0153 int atbs_1[] = {
0154 GLX_RGBA,
0155 GLX_RED_SIZE, 1,
0156 GLX_GREEN_SIZE, 1,
0157 GLX_BLUE_SIZE, 1,
0158 GLX_ALPHA_SIZE, 1,
0159 GLX_DEPTH_SIZE, 1,
0160 None
0161 };
0162 vinfo = ::glXChooseVisual (display,iscreen,atbs_1);
0163 if(vinfo==NULL) { //GLX_ALPHA_SIZE : problem with Xming. Try without it.
0164 int atbs_2[] = {
0165 GLX_RGBA,
0166 GLX_RED_SIZE, 1,
0167 GLX_GREEN_SIZE, 1,
0168 GLX_BLUE_SIZE, 1,
0169 GLX_DEPTH_SIZE, 1,
0170 None
0171 };
0172 vinfo = ::glXChooseVisual (display,iscreen,atbs_2);
0173 }
0174 }
0175
0176 if(vinfo==NULL) {
0177 CWarn ("Can't choose a visual.\n");
0178 } else {
0179 a_this->core.depth = vinfo->depth;
0180 athis.visual = vinfo->visual;
0181 if( (vinfo->depth ==DefaultDepth (display,iscreen)) &&
0182 (vinfo->visual==DefaultVisual(display,iscreen)) ) {
0183 a_this->core.colormap = XDefaultColormap (display,iscreen);
0184 athis.installColormap = False;
0185 } else {
0186 a_this->core.colormap =
0187 XCreateColormap (display,XRootWindow(display,iscreen),vinfo->visual, AllocNone);
0188 athis.installColormap = True;
0189 }
0190 if(a_this->core.colormap==0L) {
0191 CWarn ("Can't get/create a X colormap.\n");
0192 }
0193 athis.glContext = ::glXCreateContext (display,vinfo,NULL,GL_TRUE);
0194 if(athis.glContext==NULL) {
0195 athis.glContext = ::glXCreateContext (display,vinfo,NULL,GL_FALSE);
0196 if(athis.glContext==NULL) {
0197 CWarn ("Can't create a GLX context.\n");
0198 }
0199 }
0200 ::XFree(vinfo);
0201 }
0202
0203 ::XtAddEventHandler
0204 (a_this,ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|KeyPressMask|KeyReleaseMask,0,event_handler,NULL);
0205 }
0206
0207 static void realize_widget(Widget a_this,XtValueMask* a_mask,XSetWindowAttributes* a_watbs) {
0208
0209 // Have to create window ourselves due to OpenGL that compells it's visual.
0210 // In principle colormap is correctly set in a_watbsy.
0211
0212 OpenGLAreaPart& athis = _athis(a_this);
0213
0214 ::XtCreateWindow(a_this,(unsigned int)InputOutput,athis.visual,*a_mask,a_watbs);
0215
0216 // Call the Realize procedure (XtInheritRealize) :
0217 if(widget_class()->core_class.superclass->core_class.realize!=NULL)
0218 (widget_class()->core_class.superclass->core_class.realize)(a_this, a_mask, a_watbs);
0219
0220 // If window is delete, all seems ok :
0221 if(athis.installColormap==True) install_colormap(a_this);
0222
0223 }
0224
0225 static void destroy_widget(Widget a_this) {
0226 OpenGLAreaPart& athis = _athis(a_this);
0227 if(athis.installColormap==True) {
0228 uninstall_colormap (a_this);
0229 athis.installColormap = False;
0230 ::XFreeColormap(XtDisplay(a_this),a_this->core.colormap);
0231 }
0232 if(athis.glContext!=NULL) {
0233 ::glXMakeCurrent(XtDisplay(a_this),None,NULL);
0234 ::glXDestroyContext(XtDisplay(a_this),athis.glContext);
0235 athis.glContext = NULL;
0236 }
0237 }
0238
0239 static Boolean set_values(Widget a_current,Widget,Widget a_this,ArgList,Cardinal*) {
0240 OpenGLAreaPart& athis = _athis(a_this);
0241 if(athis.doubleBufferOn != ((OpenGLAreaWidget)a_current)->openGLArea.doubleBufferOn) {
0242 // Can't change buffering here if X window is created.
0243 // With OpenGL, buffering fix parameter of the X window.
0244 // Buffering must be choosen before the execution of the
0245 // Realize method that create the window.
0246 if(XtIsRealized(a_this) && (athis.installColormap==True)) {
0247 CWarn("Can't change buffering after \"realization\" of the widget.\n");
0248 athis.doubleBufferOn = ((OpenGLAreaWidget)a_current)->openGLArea.doubleBufferOn;
0249 }
0250 }
0251 return False;
0252 }
0253
0254 static void change_widget_size(Widget a_this) {
0255 // Call the Resize procedure (XtInheritResize) :
0256 if(widget_class()->core_class.superclass->core_class.resize!=NULL)
0257 (widget_class()->core_class.superclass->core_class.resize)(a_this);
0258 }
0259
0260 static void draw_widget(Widget a_this,XEvent* a_event,Region a_region) {
0261 if(widget_class()->core_class.superclass->core_class.expose!=NULL)
0262 (widget_class()->core_class.superclass->core_class.expose)(a_this,a_event,a_region);
0263
0264 if(make_current(a_this)==1) {
0265 XoAnyCallbackStruct value;
0266 value.reason = XoCR_PAINT;
0267 value.event = a_event;
0268 ::XtCallCallbacks(a_this,XoNpaintCallback,(XtPointer)&value);
0269 ::glXSwapBuffers(XtDisplay(a_this),XtWindow(a_this));
0270 ::glXMakeCurrent(XtDisplay(a_this),None,NULL);
0271 }
0272 }
0273
0274 protected:
0275 static OpenGLAreaPart& _athis(Widget a_this) {return *(&(((OpenGLAreaWidget)a_this)->openGLArea));}
0276 static void CWarn(const char* a_msg) {
0277 ::printf("%s",a_msg);
0278 }
0279 static void CWarnF(const char* a_format,...) {
0280 va_list args;
0281 va_start(args,a_format);
0282 ::vprintf(a_format,args);
0283 va_end(args);
0284 }
0285 static int make_current(Widget a_this) {
0286 if(!XtIsRealized(a_this)) return 0;
0287 OpenGLAreaPart& athis = _athis(a_this);
0288 if(athis.glContext==NULL) return 0;
0289 return (int)::glXMakeCurrent(XtDisplay(a_this),XtWindow(a_this),athis.glContext);
0290 }
0291
0292 static void event_handler(Widget a_this,XtPointer,XEvent* a_event ,Boolean*) {
0293 XoAnyCallbackStruct value;
0294 value.reason = XoCR_EVENT;
0295 value.event = a_event;
0296 ::XtCallCallbacks(a_this,XoNeventCallback,(XtPointer)&value);
0297 }
0298
0299 static void install_colormap(Widget a_this) {
0300 // From Mesa/widgets/GLwDrawingArea.c/post_colormap routine.
0301 // Could use also XtSetWMColormapWindows.
0302 if( !XtIsWidget(a_this) || !XtIsRealized(a_this) ) return;
0303 Widget shell = get_shell(a_this);
0304 if(shell==NULL) return;
0305 Display* display = XtDisplay (a_this);
0306 Window wthis = XtWindow (a_this);
0307 Window wshell = XtWindow (shell);
0308 Window* ws = NULL;
0309 int wn = 0;
0310 ::XGetWMColormapWindows (display,wshell, &ws, &wn);
0311 // Check if colormap of this is a colormap of a Window in list :
0312 XWindowAttributes watbs;
0313 XGetWindowAttributes (display,wthis,&watbs);
0314 Colormap cmapthis = watbs.colormap;
0315 int found = -1;
0316 for(int count=0;count<wn;count++) {
0317 Colormap cmap;
0318 XGetWindowAttributes (display,ws[count],&watbs);
0319 cmap = watbs.colormap;
0320 if(cmap==cmapthis) {
0321 ::XFree (ws);
0322 return;
0323 }
0324 if(ws[count]==wshell) {
0325 found = count;
0326 }
0327 }
0328 // Have to add window of this in list :
0329 if(wn==0) {
0330 if(ws!=NULL) ::XFree(ws);
0331 ws = (Window*)::malloc( 2 * sizeof(Window));
0332 } else {
0333 ws = (Window*)::realloc(ws,(wn + 2) * sizeof(Window));
0334 }
0335 if(ws==NULL) return;
0336 if(found==-1) {
0337 // Window of shell not in list :
0338 ws[wn] = wthis; wn++;
0339 ws[wn] = wshell;wn++;
0340 } else {
0341 ws[found] = wthis;
0342 ws[wn] = wshell; wn++; // Shell must be last.
0343 }
0344 if (::XSetWMColormapWindows(display,wshell, ws, wn)==0) {
0345 CWarnF ("install_colormap: can't install colormap of %s in %s.\n",XtName(a_this),XtName(shell));
0346 }
0347 ::free(ws);
0348 }
0349
0350 static void uninstall_colormap(Widget a_this) {
0351 if( !XtIsWidget(a_this) || !XtIsRealized(a_this) ) return;
0352 Widget shell = get_shell (a_this);
0353 if(shell==NULL) return;
0354 Display* display = XtDisplay (a_this);
0355 Window wthis = XtWindow (a_this);
0356 Window wshell = XtWindow (shell);
0357 Window* ws = NULL;
0358 int wn = 0;
0359 ::XGetWMColormapWindows (display,wshell, &ws, &wn);
0360 if( (wn==0) || (ws==NULL) ) return;
0361 Window* nws = (Window*)::malloc( wn * sizeof(Window));
0362 if(nws==NULL) {
0363 ::XFree (ws);
0364 return;
0365 }
0366 int nwn = 0;
0367 for(int count=0;count<wn;count++) {
0368 if(ws[count]!=wthis) {
0369 nws[nwn] = ws[count];
0370 nwn++;
0371 }
0372 }
0373 if(wn!=nwn) {
0374 if (::XSetWMColormapWindows(display,wshell, nws, nwn)==0) {
0375 CWarnF("uninstall_colormap: can't install colormap of %s in %s.\n",XtName(a_this),XtName(shell));
0376 }
0377 }
0378 ::XFree (ws);
0379 ::free (nws);
0380 }
0381
0382 static Widget get_shell(Widget a_this) {
0383 Widget widget = a_this;
0384 while(1) {
0385 if(widget==NULL) return NULL;
0386 if(XtIsShell(widget)) return widget;
0387 widget = XtParent(widget);
0388 }
0389 }
0390
0391 public:
0392 static WidgetClass widget_class() {
0393 static XtResource s_resources[] = {
0394 {(String)XoN_doubleBufferOn(),(String)XoC_DoubleBufferOn(),XtRBoolean,sizeof(Boolean),
0395 XtOffset(OpenGLAreaWidget,openGLArea.doubleBufferOn),XtRImmediate,(XtPointer)True},
0396 {(String)XoN_paintCallback(),XtCCallback,XtRCallback,sizeof(XtCallbackList),
0397 XtOffset(OpenGLAreaWidget,openGLArea.paintCallback),XtRImmediate,(XtPointer)NULL},
0398 {(String)XoN_eventCallback(),XtCCallback,XtRCallback,sizeof(XtCallbackList),
0399 XtOffset(OpenGLAreaWidget,openGLArea.eventCallback),XtRImmediate,(XtPointer)NULL}
0400 };
0401
0402 static OpenGLAreaClassRec s_openGLAreaClassRec = {
0403 // Core Class Part :
0404 {
0405 (WidgetClass) &compositeClassRec, // pointer to superclass ClassRec
0406 (String)class_name(), // widget resource class name
0407 sizeof(OpenGLAreaRec), // size in bytes of widget record
0408 initialize_class, // class_initialize
0409 NULL, // dynamic initialization
0410 FALSE, // has class been initialized?
0411 initialize_widget, // initialize
0412 NULL, // notify that initialize called
0413 realize_widget, // XCreateWindow for widget
0414 NULL, // widget semantics name to proc mapWidget
0415 0, // number of entries in actions
0416 s_resources, // resources for subclass fields
0417 XtNumber(s_resources), // number of entries in resources
0418 NULLQUARK, // resource class quarkified
0419 TRUE, // compress MotionNotify for widget
0420 TRUE, // compress Expose events for widget
0421 TRUE, // compress enter and leave events
0422 TRUE, // select for VisibilityNotify
0423 destroy_widget, // free data for subclass pointers
0424 change_widget_size, // geom manager changed widget size
0425 draw_widget, // rediplay window
0426 set_values, // set subclass resource values
0427 NULL, // notify that SetValues called
0428 XtInheritSetValuesAlmost, // SetValues got "Almost" geo reply
0429 NULL, // notify that get_values called
0430 XtInheritAcceptFocus, // assign input focus to widget
0431 XtVersion, // version of intrinsics used
0432 NULL, // list of callback offsets
0433 XtInheritTranslations, // translations
0434 XtInheritQueryGeometry, // return preferred geometry
0435 XtInheritDisplayAccelerator, // display your accelerator
0436 NULL // pointer to extension record
0437 },
0438 // Composite Class Part :
0439 {
0440 XtInheritGeometryManager, // geometry manager for children
0441 XtInheritChangeManaged, // change managed state of child
0442 XtInheritInsertChild, // physically add child to parent
0443 XtInheritDeleteChild, // physically remove child
0444 NULL // pointer to extension record
0445 },
0446 // OpenGLArea :
0447 {
0448 NULL
0449 }
0450 };
0451 return (WidgetClass)&s_openGLAreaClassRec;
0452 }
0453 };
0454
0455 }}
0456
0457 #endif