Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef toolx_Xt_OpenGLArea 5 #define toolx_Xt_OpenGLArea 6 7 #include <X11/IntrinsicP.h> 8 #include <X11/CoreP.h> 9 #include <X11/CompositeP.h> 10 #include <X11/StringDefs.h> 11 12 #include <GL/glx.h> 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <stdarg.h> 17 18 namespace toolx { 19 namespace Xt { 20 21 /////////////////////////////////////////////////////////// 22 /////////////////////////////////////////////////////////// 23 /////////////////////////////////////////////////////////// 24 25 typedef struct _OpenGLAreaClassRec* OpenGLAreaWidgetClass; 26 typedef struct _OpenGLAreaRec* OpenGLAreaWidget; 27 28 typedef struct { 29 int reason; 30 XEvent* event; 31 } XoAnyCallbackStruct; 32 33 #define XoCR_PAINT 1 34 #define XoCR_EVENT 2 35 36 #define XoNdoubleBufferOn toolx::Xt::OpenGLArea::XoN_doubleBufferOn() 37 #define XoNpaintCallback toolx::Xt::OpenGLArea::XoN_paintCallback() 38 #define XoNeventCallback toolx::Xt::OpenGLArea::XoN_eventCallback() 39 40 /////////////////////////////////////////////////////////// 41 /////////////////////////////////////////////////////////// 42 /////////////////////////////////////////////////////////// 43 44 typedef struct { 45 void* extension; 46 } OpenGLAreaClassPart; 47 48 typedef struct _OpenGLAreaClassRec { 49 CoreClassPart core_class; 50 CompositeClassPart composite_class; 51 OpenGLAreaClassPart openGLArea_class; 52 } OpenGLAreaClassRec; 53 54 typedef struct { 55 Boolean doubleBufferOn; 56 XtCallbackList paintCallback; 57 XtCallbackList eventCallback; 58 Visual* visual; 59 Boolean installColormap; 60 GLXContext glContext; 61 } OpenGLAreaPart; 62 63 typedef struct _OpenGLAreaRec { 64 CorePart core; 65 CompositePart composite; 66 OpenGLAreaPart openGLArea; 67 } OpenGLAreaRec; 68 69 /////////////////////////////////////////////////////////// 70 /////////////////////////////////////////////////////////// 71 /////////////////////////////////////////////////////////// 72 73 class OpenGLArea { 74 protected: 75 static const char* class_name() {static const char* s_s = "OpenGLArea";return s_s;} 76 static const char* XoC_DoubleBufferOn() {static const char* s_s = "DoubleBufferOn";return s_s;} 77 public: 78 static const char* XoN_doubleBufferOn() {static const char* s_s = "doubleBufferOn";return s_s;} 79 static const char* XoN_paintCallback() {static const char* s_s = "paintCallback";return s_s;} 80 static const char* XoN_eventCallback() {static const char* s_s = "eventCallback";return s_s;} 81 public: 82 static void paint(Widget a_this) { 83 if(!XtIsRealized(a_this)) return; 84 if(make_current(a_this)==1) { 85 XoAnyCallbackStruct value; 86 value.reason = XoCR_PAINT; 87 value.event = 0; 88 ::XtCallCallbacks(a_this,XoNpaintCallback,(XtPointer)&value); 89 ::glXSwapBuffers(XtDisplay(a_this),XtWindow(a_this)); 90 ::glXMakeCurrent(XtDisplay(a_this),None,NULL); 91 } 92 } 93 protected: 94 static void initialize_class(void) {} 95 96 static void initialize_widget(Widget a_request,Widget a_this,ArgList,Cardinal*) { 97 if(a_request->core.width<=0) a_this->core.width = 100; 98 if(a_request->core.height<=0) a_this->core.height = 100; 99 100 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 101 ::printf ("debug : OpenGLArea : InitializeWidget : %s\n",::XtName(a_this)); 102 #endif 103 104 OpenGLAreaPart& athis = _athis(a_this); 105 athis.visual = CopyFromParent; 106 athis.installColormap = False; 107 athis.glContext = NULL; 108 109 Display* display; 110 Screen* screen; 111 int iscreen; 112 XVisualInfo* vinfo; 113 display = XtDisplay(a_this); 114 screen = XtScreen(a_this); 115 iscreen = XScreenNumberOfScreen(screen); 116 117 {int error,event; 118 if(::glXQueryExtension(display,&error,&event)==0) { 119 CWarn ("X server does not have OpenGL extensions.\n"); 120 }} 121 122 if(athis.doubleBufferOn==True) { 123 int atbs_1[] = { 124 GLX_RGBA, 125 GLX_RED_SIZE, 1, 126 GLX_GREEN_SIZE, 1, 127 GLX_BLUE_SIZE, 1, 128 GLX_ALPHA_SIZE, 1, 129 GLX_DEPTH_SIZE, 1, 130 GLX_DOUBLEBUFFER, 131 None 132 }; 133 vinfo = ::glXChooseVisual (display,iscreen,atbs_1); 134 if(vinfo==NULL) { //GLX_ALPHA_SIZE : problem with Xming. Try without it. 135 int atbs_2[] = { 136 GLX_RGBA, 137 GLX_RED_SIZE, 1, 138 GLX_GREEN_SIZE, 1, 139 GLX_BLUE_SIZE, 1, 140 GLX_DEPTH_SIZE, 1, 141 GLX_DOUBLEBUFFER, 142 None 143 }; 144 vinfo = ::glXChooseVisual (display,iscreen,atbs_2); 145 } 146 } else { 147 int atbs_1[] = { 148 GLX_RGBA, 149 GLX_RED_SIZE, 1, 150 GLX_GREEN_SIZE, 1, 151 GLX_BLUE_SIZE, 1, 152 GLX_ALPHA_SIZE, 1, 153 GLX_DEPTH_SIZE, 1, 154 None 155 }; 156 vinfo = ::glXChooseVisual (display,iscreen,atbs_1); 157 if(vinfo==NULL) { //GLX_ALPHA_SIZE : problem with Xming. Try without it. 158 int atbs_2[] = { 159 GLX_RGBA, 160 GLX_RED_SIZE, 1, 161 GLX_GREEN_SIZE, 1, 162 GLX_BLUE_SIZE, 1, 163 GLX_DEPTH_SIZE, 1, 164 None 165 }; 166 vinfo = ::glXChooseVisual (display,iscreen,atbs_2); 167 } 168 } 169 170 if(vinfo==NULL) { 171 CWarn ("Can't choose a visual.\n"); 172 } else { 173 a_this->core.depth = vinfo->depth; 174 athis.visual = vinfo->visual; 175 if( (vinfo->depth ==DefaultDepth (display,iscreen)) && 176 (vinfo->visual==DefaultVisual(display,iscreen)) ) { 177 a_this->core.colormap = XDefaultColormap (display,iscreen); 178 athis.installColormap = False; 179 } else { 180 a_this->core.colormap = 181 XCreateColormap (display,XRootWindow(display,iscreen),vinfo->visual, AllocNone); 182 athis.installColormap = True; 183 } 184 if(a_this->core.colormap==0L) { 185 CWarn ("Can't get/create a X colormap.\n"); 186 } 187 athis.glContext = ::glXCreateContext (display,vinfo,NULL,GL_TRUE); 188 if(athis.glContext==NULL) { 189 athis.glContext = ::glXCreateContext (display,vinfo,NULL,GL_FALSE); 190 if(athis.glContext==NULL) { 191 CWarn ("Can't create a GLX context.\n"); 192 } 193 } 194 ::XFree(vinfo); 195 } 196 197 ::XtAddEventHandler 198 (a_this,ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|KeyPressMask|KeyReleaseMask,0,event_handler,NULL); 199 200 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 201 printf("debug : OpenGLArea : InitializeWidget : end\n"); 202 #endif 203 } 204 205 static void realize_widget(Widget a_this,XtValueMask* a_mask,XSetWindowAttributes* a_watbs) { 206 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 207 printf("debug : OpenGLArea : realize_widget : %s\n",XtName(a_this)); 208 #endif 209 210 // Have to create window ourselves due to OpenGL that compells it's visual. 211 // In principle colormap is correctly set in a_watbsy. 212 213 OpenGLAreaPart& athis = _athis(a_this); 214 215 ::XtCreateWindow(a_this,(unsigned int)InputOutput,athis.visual,*a_mask,a_watbs); 216 217 // Call the Realize procedure (XtInheritRealize) : 218 if(widget_class()->core_class.superclass->core_class.realize!=NULL) 219 (widget_class()->core_class.superclass->core_class.realize)(a_this, a_mask, a_watbs); 220 221 // If window is delete, all seems ok : 222 if(athis.installColormap==True) install_colormap(a_this); 223 224 //make_current(a_this); 225 226 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 227 printf("debug : OpenGLArea : realize_widget : end\n"); 228 #endif 229 } 230 231 static void destroy_widget(Widget a_this) { 232 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 233 printf("debug : OpenGLArea : destroy_widget : begin\n"); 234 #endif 235 OpenGLAreaPart& athis = _athis(a_this); 236 if(athis.installColormap==True) { 237 uninstall_colormap (a_this); 238 athis.installColormap = False; 239 ::XFreeColormap(XtDisplay(a_this),a_this->core.colormap); 240 } 241 if(athis.glContext!=NULL) { 242 ::glXMakeCurrent(XtDisplay(a_this),None,NULL); 243 ::glXDestroyContext(XtDisplay(a_this),athis.glContext); 244 athis.glContext = NULL; 245 } 246 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 247 printf("debug : OpenGLArea : destroy_widget : end\n"); 248 #endif 249 } 250 251 static Boolean set_values(Widget a_current,Widget,Widget a_this,ArgList,Cardinal*) { 252 OpenGLAreaPart& athis = _athis(a_this); 253 if(athis.doubleBufferOn != ((OpenGLAreaWidget)a_current)->openGLArea.doubleBufferOn) { 254 // Can't change buffering here if X window is created. 255 // With OpenGL, buffering fix parameter of the X window. 256 // Buffering must be choosen before the execution of the 257 // Realize method that create the window. 258 if(XtIsRealized(a_this) && (athis.installColormap==True)) { 259 CWarn("Can't change buffering after \"realization\" of the widget.\n"); 260 athis.doubleBufferOn = ((OpenGLAreaWidget)a_current)->openGLArea.doubleBufferOn; 261 } 262 } 263 return False; 264 } 265 266 static void change_widget_size(Widget a_this) { 267 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 268 printf("debug : OpenGLArea : change_widget_size : %s\n",XtName(a_this)); 269 #endif 270 271 // Call the Resize procedure (XtInheritResize) : 272 if(widget_class()->core_class.superclass->core_class.resize!=NULL) 273 (widget_class()->core_class.superclass->core_class.resize)(a_this); 274 275 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 276 printf("debug : OpenGLArea : change_widget_size : end\n"); 277 #endif 278 } 279 280 static void draw_widget(Widget a_this,XEvent* a_event,Region a_region) { 281 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 282 printf("debug : OpenGLArea : draw_widget : %s\n",XtName(a_this)); 283 #endif 284 285 if(widget_class()->core_class.superclass->core_class.expose!=NULL) 286 (widget_class()->core_class.superclass->core_class.expose)(a_this,a_event,a_region); 287 288 if(make_current(a_this)==1) { 289 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 290 printf("debug : OpenGLArea : draw_widget : %s : make_current ok : call paintCallback...\n",XtName(a_this)); 291 #endif 292 XoAnyCallbackStruct value; 293 value.reason = XoCR_PAINT; 294 value.event = a_event; 295 ::XtCallCallbacks(a_this,XoNpaintCallback,(XtPointer)&value); 296 ::glXSwapBuffers(XtDisplay(a_this),XtWindow(a_this)); 297 ::glXMakeCurrent(XtDisplay(a_this),None,NULL); 298 } 299 300 #ifdef TOOLX_XT_OPENGLAREA_DEBUG 301 printf("debug : OpenGLArea : draw_widget : end\n"); 302 #endif 303 } 304 305 protected: 306 static OpenGLAreaPart& _athis(Widget a_this) {return *(&(((OpenGLAreaWidget)a_this)->openGLArea));} 307 static void CWarn(const char* a_msg) { 308 ::printf("%s",a_msg); 309 } 310 static void CWarnF(const char* a_format,...) { 311 va_list args; 312 va_start(args,a_format); 313 ::vprintf(a_format,args); 314 va_end(args); 315 } 316 static int make_current(Widget a_this) { 317 if(!XtIsRealized(a_this)) return 0; 318 OpenGLAreaPart& athis = _athis(a_this); 319 if(athis.glContext==NULL) return 0; 320 return (int)::glXMakeCurrent(XtDisplay(a_this),XtWindow(a_this),athis.glContext); 321 } 322 323 static void event_handler(Widget a_this,XtPointer,XEvent* a_event ,Boolean*) { 324 XoAnyCallbackStruct value; 325 value.reason = XoCR_EVENT; 326 value.event = a_event; 327 ::XtCallCallbacks(a_this,XoNeventCallback,(XtPointer)&value); 328 } 329 330 static void install_colormap(Widget a_this) { 331 // From Mesa/widgets/GLwDrawingArea.c/post_colormap routine. 332 // Could use also XtSetWMColormapWindows. 333 if( !XtIsWidget(a_this) || !XtIsRealized(a_this) ) return; 334 Widget shell = get_shell(a_this); 335 if(shell==NULL) return; 336 Display* display = XtDisplay (a_this); 337 Window wthis = XtWindow (a_this); 338 Window wshell = XtWindow (shell); 339 Window* ws = NULL; 340 int wn = 0; 341 ::XGetWMColormapWindows (display,wshell, &ws, &wn); 342 // Check if colormap of this is a colormap of a Window in list : 343 XWindowAttributes watbs; 344 XGetWindowAttributes (display,wthis,&watbs); 345 Colormap cmapthis = watbs.colormap; 346 int found = -1; 347 for(int count=0;count<wn;count++) { 348 Colormap cmap; 349 XGetWindowAttributes (display,ws[count],&watbs); 350 cmap = watbs.colormap; 351 if(cmap==cmapthis) { 352 ::XFree (ws); 353 return; 354 } 355 if(ws[count]==wshell) { 356 found = count; 357 } 358 } 359 // Have to add window of this in list : 360 if(wn==0) { 361 if(ws!=NULL) ::XFree(ws); 362 ws = (Window*)::malloc( 2 * sizeof(Window)); 363 } else { 364 ws = (Window*)::realloc(ws,(wn + 2) * sizeof(Window)); 365 } 366 if(ws==NULL) return; 367 if(found==-1) { 368 // Window of shell not in list : 369 ws[wn] = wthis; wn++; 370 ws[wn] = wshell;wn++; 371 } else { 372 ws[found] = wthis; 373 ws[wn] = wshell; wn++; // Shell must be last. 374 } 375 if (::XSetWMColormapWindows(display,wshell, ws, wn)==0) { 376 CWarnF ("install_colormap: can't install colormap of %s in %s.\n",XtName(a_this),XtName(shell)); 377 } 378 ::free(ws); 379 } 380 381 static void uninstall_colormap(Widget a_this) { 382 if( !XtIsWidget(a_this) || !XtIsRealized(a_this) ) return; 383 Widget shell = get_shell (a_this); 384 if(shell==NULL) return; 385 Display* display = XtDisplay (a_this); 386 Window wthis = XtWindow (a_this); 387 Window wshell = XtWindow (shell); 388 Window* ws = NULL; 389 int wn = 0; 390 ::XGetWMColormapWindows (display,wshell, &ws, &wn); 391 if( (wn==0) || (ws==NULL) ) return; 392 Window* nws = (Window*)::malloc( wn * sizeof(Window)); 393 if(nws==NULL) { 394 ::XFree (ws); 395 return; 396 } 397 int nwn = 0; 398 for(int count=0;count<wn;count++) { 399 if(ws[count]!=wthis) { 400 nws[nwn] = ws[count]; 401 nwn++; 402 } 403 } 404 if(wn!=nwn) { 405 if (::XSetWMColormapWindows(display,wshell, nws, nwn)==0) { 406 CWarnF("uninstall_colormap: can't install colormap of %s in %s.\n",XtName(a_this),XtName(shell)); 407 } 408 } 409 ::XFree (ws); 410 ::free (nws); 411 } 412 413 static Widget get_shell(Widget a_this) { 414 Widget widget = a_this; 415 while(1) { 416 if(widget==NULL) return NULL; 417 if(XtIsShell(widget)) return widget; 418 widget = XtParent(widget); 419 } 420 } 421 422 public: 423 static WidgetClass widget_class() { 424 static XtResource s_resources[] = { 425 {(String)XoN_doubleBufferOn(),(String)XoC_DoubleBufferOn(),XtRBoolean,sizeof(Boolean), 426 XtOffset(OpenGLAreaWidget,openGLArea.doubleBufferOn),XtRImmediate,(XtPointer)True}, 427 {(String)XoN_paintCallback(),XtCCallback,XtRCallback,sizeof(XtCallbackList), 428 XtOffset(OpenGLAreaWidget,openGLArea.paintCallback),XtRImmediate,(XtPointer)NULL}, 429 {(String)XoN_eventCallback(),XtCCallback,XtRCallback,sizeof(XtCallbackList), 430 XtOffset(OpenGLAreaWidget,openGLArea.eventCallback),XtRImmediate,(XtPointer)NULL} 431 }; 432 433 static OpenGLAreaClassRec s_openGLAreaClassRec = { 434 // Core Class Part : 435 { 436 (WidgetClass) &compositeClassRec, // pointer to superclass ClassRec 437 (String)class_name(), // widget resource class name 438 sizeof(OpenGLAreaRec), // size in bytes of widget record 439 initialize_class, // class_initialize 440 NULL, // dynamic initialization 441 FALSE, // has class been initialized? 442 initialize_widget, // initialize 443 NULL, // notify that initialize called 444 realize_widget, // XCreateWindow for widget 445 NULL, // widget semantics name to proc mapWidget 446 0, // number of entries in actions 447 s_resources, // resources for subclass fields 448 XtNumber(s_resources), // number of entries in resources 449 NULLQUARK, // resource class quarkified 450 TRUE, // compress MotionNotify for widget 451 TRUE, // compress Expose events for widget 452 TRUE, // compress enter and leave events 453 TRUE, // select for VisibilityNotify 454 destroy_widget, // free data for subclass pointers 455 change_widget_size, // geom manager changed widget size 456 draw_widget, // rediplay window 457 set_values, // set subclass resource values 458 NULL, // notify that SetValues called 459 XtInheritSetValuesAlmost, // SetValues got "Almost" geo reply 460 NULL, // notify that get_values called 461 XtInheritAcceptFocus, // assign input focus to widget 462 XtVersion, // version of intrinsics used 463 NULL, // list of callback offsets 464 XtInheritTranslations, // translations 465 XtInheritQueryGeometry, // return preferred geometry 466 XtInheritDisplayAccelerator, // display your accelerator 467 NULL // pointer to extension record 468 }, 469 // Composite Class Part : 470 { 471 XtInheritGeometryManager, // geometry manager for children 472 XtInheritChangeManaged, // change managed state of child 473 XtInheritInsertChild, // physically add child to parent 474 XtInheritDeleteChild, // physically remove child 475 NULL // pointer to extension record 476 }, 477 // OpenGLArea : 478 { 479 NULL 480 } 481 }; 482 return (WidgetClass)&s_openGLAreaClassRec; 483 } 484 }; 485 486 }} 487 488 489 #endif