00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <vrj/vrjConfig.h>
00034
00035 #include <X11/Xlib.h>
00036 #include <X11/Xutil.h>
00037 #include <GL/glx.h>
00038 #include <vector>
00039
00040 #include <vpr/vpr.h>
00041 #include <jccl/Config/ConfigElement.h>
00042
00043 #include <vrj/Draw/OGL/GlWindow.h>
00044 #include <vrj/Kernel/Kernel.h>
00045 #include <vrj/Util/Debug.h>
00046 #include <vrj/Display/Display.h>
00047 #include <vrj/Display/DisplayManager.h>
00048
00049 #include <vrj/Draw/OGL/GlWindowXWin.h>
00050
00051 #include <stdexcept>
00052
00053 namespace
00054 {
00055 class glwinx_OpenFailureException : public std::runtime_error
00056 {
00057 public:
00058 glwinx_OpenFailureException() throw()
00059 : std::runtime_error("Failed to open glx window")
00060 {;}
00061 ~glwinx_OpenFailureException() throw() {;}
00062 };
00063 }
00064
00065 namespace vrj
00066 {
00067
00068 GlWindowXWin::GlWindowXWin()
00069 : GlWindow(), mXDisplay(NULL), mVisualInfo(NULL), mGlxContext(NULL),
00070 mXWindow(0), mWindowName(""), mPipe(-1), mXDisplayName("")
00071 {
00072 window_is_open = false;
00073 window_width = window_height = -1;
00074 }
00075
00076 GlWindowXWin::~GlWindowXWin()
00077 {
00078 close();
00079 }
00080
00081 int GlWindowXWin::open()
00082 {
00083
00084
00085
00086
00087
00088
00089
00090 ::XEvent fooevent;
00091 ::XSetWindowAttributes w_attrib;
00092 int screen;
00093 char* foo;
00094 ::XSizeHints *sizehints;
00095 ::XClassHint *classhint;
00096 unsigned long event_mask(0);
00097 bool ret_val(true);
00098
00099 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_STATE_LVL) << "glxWindow: Open window\n" << vprDEBUG_FLUSH;
00100
00101 if ( window_is_open )
00102 return true;
00103
00104 if ( window_width == -1 )
00105 {
00106 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00107 << clrOutNORM(clrRED,"ERROR:")
00108 << "vrj::GlWindowXWin: Window has not been configured\n"
00109 << vprDEBUG_FLUSH;
00110 return false;
00111 }
00112
00113 if ( ! (mXDisplay = ::XOpenDisplay(mXDisplayName.c_str())) )
00114 {
00115 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00116 << clrOutNORM(clrRED,"ERROR:")
00117 << "vrj::GlWindowXWin: Unable to open display '" << mXDisplayName
00118 << "'.\n" << vprDEBUG_FLUSH;
00119 return false;
00120 }
00121
00122 try
00123 {
00124 screen = DefaultScreen(mXDisplay);
00125
00126
00127 if ( (mVisualInfo = getGlxVisInfo(mXDisplay, screen)) == NULL )
00128 {
00129 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00130 << clrOutNORM(clrRED,"ERROR:") << "glXChooseVisual failed\n"
00131 << vprDEBUG_FLUSH;
00132 throw glwinx_OpenFailureException();
00133 }
00134
00135 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00136 << "Visual ID: 0x" << std::hex << mVisualInfo->visualid << std::dec
00137 << std::endl << vprDEBUG_FLUSH;
00138
00139
00140 w_attrib.colormap = ::XCreateColormap(mXDisplay,
00141 RootWindow(mXDisplay, screen),
00142 mVisualInfo->visual,
00143 AllocNone);
00144
00145 if ( w_attrib.colormap == 0 )
00146 {
00147 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00148 << clrOutNORM(clrRED,"ERROR:")
00149 << "vrj::GlWindowXWin: XCreateColorMap failed on '" << mXDisplayName
00150 << "'.\n" << vprDEBUG_FLUSH;
00151 throw glwinx_OpenFailureException();
00152 }
00153
00154 event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
00155 KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
00156 ButtonMotionMask | PointerMotionMask | StructureNotifyMask;
00157 w_attrib.event_mask = event_mask;
00158 w_attrib.border_pixel = 0x0;
00159
00160
00161 ::XWindowAttributes winattrs;
00162 ::XGetWindowAttributes(mXDisplay, RootWindow(mXDisplay, screen), &winattrs);
00163
00164
00165 mXWindow = ::XCreateWindow(mXDisplay, RootWindow(mXDisplay, screen),
00166 origin_x, winattrs.height - origin_y - window_height,
00167 window_width, window_height, 0,
00168 mVisualInfo->depth, InputOutput,
00169 mVisualInfo->visual,
00170 CWEventMask | CWColormap | CWBorderPixel,
00171 &w_attrib);
00172
00173 if ( 0 == mXWindow )
00174 {
00175 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CRITICAL_LVL)
00176 << clrOutNORM(clrRED,"ERROR:")
00177 << "vrj::GlWindowXWin: Couldn't create window for " << mXDisplayName
00178 << std::endl << vprDEBUG_FLUSH;
00179 throw glwinx_OpenFailureException();
00180 }
00181
00182 createEmptyCursor(mXDisplay, mXWindow);
00183
00184
00185
00186
00187
00188
00189 classhint = ::XAllocClassHint();
00190 classhint->res_name = (char*)mWindowName.c_str();
00191 classhint->res_class = "VRJ GLX";
00192
00193
00194
00195
00196 ::XTextProperty w_name;
00197 foo = (char*) mWindowName.c_str();
00198 ::XStringListToTextProperty(&foo, 1, &w_name);
00199
00200
00201 sizehints = XAllocSizeHints();
00202 sizehints->flags = USPosition;
00203
00204 ::XSetWMProperties(mXDisplay, mXWindow, &w_name, &w_name,
00205 NULL, 0, sizehints, NULL, classhint);
00206
00207 ::XFree(w_name.value);
00208 ::XFree(classhint);
00209 ::XFree(sizehints);
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 if ( !border )
00221 {
00222 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_HVERB_LVL) << "attempting to make window borderless"
00223 << std::endl << vprDEBUG_FLUSH;
00224 Atom MotifHints = XInternAtom(mXDisplay, "_MOTIF_WM_HINTS", 0);
00225 if ( MotifHints == None )
00226 {
00227 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CRITICAL_LVL)
00228 << clrOutNORM(clrRED,"ERROR:")
00229 << "vrj::GlWindowXWin: Could not get X atom for _MOTIF_WM_HINTS."
00230 << std::endl << vprDEBUG_FLUSH;
00231 }
00232 else
00233 {
00234 MotifWmHints hints;
00235 hints.flags = MWM_HINTS_DECORATIONS;
00236 hints.decorations = 0;
00237 XChangeProperty(mXDisplay, mXWindow, MotifHints, MotifHints, 32,
00238 PropModeReplace, (unsigned char *) &hints, 4);
00239 }
00240 }
00241
00242
00243
00244
00245 ::XSelectInput(mXDisplay, mXWindow, event_mask);
00246 ::XMapWindow(mXDisplay, mXWindow);
00247 ::XIfEvent(mXDisplay, &fooevent, EventIsMapNotify, (XPointer)mXWindow);
00248 ::XSync(mXDisplay, 0);
00249
00250 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_VERB_LVL) << "vrj::GlWindowXWin: done mapping window\n"
00251 << vprDEBUG_FLUSH;
00252
00253
00254
00255 mGlxContext = glXCreateContext(mXDisplay, mVisualInfo, NULL, True);
00256 if ( NULL == mGlxContext )
00257 {
00258 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00259 << clrOutNORM(clrRED,"ERROR:") << "Couldn't create GlxContext for '"
00260 << mXDisplayName << "'\n" << vprDEBUG_FLUSH;
00261 throw glwinx_OpenFailureException();
00262 }
00263
00264 window_is_open = true;
00265
00266
00267 if ( true == mAreEventSource )
00268 {
00269
00270 gadget::EventWindowXWin::mWindow = mXWindow;
00271 gadget::EventWindowXWin::mVisual = mVisualInfo;
00272 gadget::EventWindowXWin::mDisplay = mXDisplay;
00273
00274
00275
00276
00277
00278
00279 gadget::Input* dev_ptr = dynamic_cast<gadget::Input*>(this);
00280
00281
00282
00283 vrj::Kernel::instance()->getInputManager()->addDevice(dev_ptr);
00284 }
00285
00286 ret_val = true;
00287 }
00288 catch (glwinx_OpenFailureException& openFailed)
00289 {
00290
00291
00292
00293 close();
00294
00295 ret_val = false;
00296 }
00297
00298 return ret_val;
00299 }
00300
00305 int GlWindowXWin::close()
00306 {
00307
00308
00309
00310
00311
00312
00313
00314 if ( true == mAreEventSource )
00315 {
00316 gadget::Input* dev_ptr = dynamic_cast<gadget::Input*>(this);
00317
00318
00319
00320
00321 vrj::Kernel::instance()->getInputManager()->removeDevice(dev_ptr);
00322 }
00323
00324 if ( mGlxContext )
00325 {
00326 makeCurrent();
00327
00328 glXMakeCurrent(mXDisplay, None, NULL);
00329 glXDestroyContext(mXDisplay, mGlxContext);
00330 mGlxContext = NULL;
00331 }
00332 if ( mXWindow )
00333 {
00334 ::XDestroyWindow(mXDisplay, mXWindow);
00335 mXWindow = 0;
00336 }
00337 if ( mVisualInfo )
00338 {
00339 ::XFree(mVisualInfo);
00340 mVisualInfo = NULL;
00341 }
00342 if ( mXDisplay )
00343 {
00344 ::XCloseDisplay(mXDisplay);
00345 mXDisplay = NULL;
00346 }
00347
00348 window_is_open = false;
00349
00350 return true;
00351
00352 }
00353
00354 void GlWindowXWin::swapBuffers()
00355 {
00356 glXSwapBuffers(mXDisplay, mXWindow);
00357 }
00358
00359 bool GlWindowXWin::makeCurrent()
00360 {
00361
00362
00363
00364 if ( !window_is_open )
00365 {
00366 return false;
00367 }
00368
00369 vprASSERT(mGlxContext != NULL);
00370 vprASSERT(mXWindow != 0);
00371 vprASSERT(mXDisplay != NULL);
00372
00373 return glXMakeCurrent(mXDisplay, mXWindow, mGlxContext);
00374 }
00375
00376 void GlWindowXWin::configWindow(vrj::Display* disp)
00377 {
00378 const char neg_one_string[] = "-1";
00379 vrj::GlWindow::configWindow(disp);
00380
00381
00382 jccl::ConfigElementPtr disp_sys_elt = DisplayManager::instance()->getDisplaySystemElement();
00383 jccl::ConfigElementPtr display_elt = disp->getConfigElement();
00384
00385 mWindowName = disp->getName();
00386 mPipe = disp->getPipe();
00387 vprASSERT(mPipe >= 0);
00388
00389
00390
00391
00392 mXDisplayName = disp_sys_elt->getProperty<std::string>("x11_pipes", mPipe);
00393
00394 if ( mXDisplayName == neg_one_string )
00395 {
00396 const std::string DISPLAY_str("DISPLAY");
00397 const char* d = getenv(DISPLAY_str.c_str());
00398 if ( NULL != d )
00399 {
00400 mXDisplayName = std::string( d );
00401 }
00402 }
00403 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_VERB_LVL) << "glxWindow::config: display name is: "
00404 << mXDisplayName << std::endl << vprDEBUG_FLUSH;
00405
00406 mAreEventSource = display_elt->getProperty<bool>("act_as_event_source");
00407
00408
00409 if ( true == mAreEventSource )
00410 {
00411
00412 jccl::ConfigElementPtr event_win_element =
00413 display_elt->getProperty<jccl::ConfigElementPtr>("event_window_device");
00414
00415
00416
00417
00418
00419 gadget::EventWindowXWin::config(event_win_element);
00420
00421
00422 gadget::EventWindowXWin::mWidth = GlWindowXWin::window_width;
00423 gadget::EventWindowXWin::mHeight = GlWindowXWin::window_height;
00424
00425 mWeOwnTheWindow = false;
00426 }
00427 }
00428
00429 bool GlWindowXWin::createHardwareSwapGroup(std::vector<vrj::GlWindow*> wins)
00430 {
00431
00432 std::vector<GlWindowXWin*> glx_wins;
00433 unsigned int i;
00434
00435 if ( wins.size() <= 0 )
00436 {
00437 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00438 << "WARNING: createHardwareSwapGroup called with no windows\n"
00439 << vprDEBUG_FLUSH;
00440 }
00441
00442 for ( i = 0; i < wins.size(); ++i )
00443 {
00444 GlWindowXWin* glx_win = dynamic_cast<GlWindowXWin*>(wins[i]);
00445 vprASSERT(glx_win != NULL);
00446 glx_wins.push_back(glx_win);
00447 }
00448
00449
00450 #ifdef VPR_OS_IRIX
00451 for ( i = 0; i < glx_wins.size(); ++i )
00452 {
00453
00454 if ( glx_wins[i] != this )
00455 {
00456 glXJoinSwapGroupSGIX(mXDisplay, mXWindow, glx_wins[i]->mXWindow);
00457 }
00458 }
00459
00460 #else
00461 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00462 << "WARNING: createHardwareSwapGroup not supported.\n" << vprDEBUG_FLUSH;
00463 #endif
00464 return true;
00465 }
00466
00467 void GlWindowXWin::checkEvents()
00468 {
00469
00470 if ( true == mAreEventSource )
00471 {
00472 gadget::EventWindowXWin::sample();
00473 }
00474
00475 }
00476
00477
00478
00479
00480 ::XVisualInfo* GlWindowXWin::getGlxVisInfo(::Display *display, int screen)
00481 {
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 int red_size(1), green_size(1), blue_size(1), alpha_size(1), db_size(1);
00496 bool want_fsaa(false);
00497
00498 jccl::ConfigElementPtr gl_fb_elt = mVrjDisplay->getGlFrameBufferConfig();
00499
00500 if ( gl_fb_elt.get() != NULL )
00501 {
00502 red_size = gl_fb_elt->getProperty<int>("red_size");
00503 green_size = gl_fb_elt->getProperty<int>("green_size");
00504 blue_size = gl_fb_elt->getProperty<int>("blue_size");
00505 alpha_size = gl_fb_elt->getProperty<int>("alpha_size");
00506 db_size = gl_fb_elt->getProperty<int>("depth_buffer_size");
00507 want_fsaa = gl_fb_elt->getProperty<bool>("fsaa_enable");
00508
00509 if ( red_size < 0 )
00510 {
00511 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_WARNING_LVL)
00512 << "WARNING: Red channel size was negative, set to: " << red_size
00513 << ". Setting to 1.\n" << vprDEBUG_FLUSH;
00514 red_size = 1;
00515 }
00516
00517 if ( green_size < 0 )
00518 {
00519 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_WARNING_LVL)
00520 << "WARNING: Green channel size was negative, set to: "
00521 << green_size << ". Setting to 1.\n" << vprDEBUG_FLUSH;
00522 green_size = 1;
00523 }
00524
00525 if ( blue_size < 0 )
00526 {
00527 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_WARNING_LVL)
00528 << "WARNING: Blue channel size was negative, set to: " << blue_size
00529 << ". Setting to 1.\n" << vprDEBUG_FLUSH;
00530 blue_size = 1;
00531 }
00532
00533 if ( alpha_size < 0 )
00534 {
00535 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_WARNING_LVL)
00536 << "WARNING: Alpha channel size was negative, set to: "
00537 << alpha_size << ". Setting to 1.\n" << vprDEBUG_FLUSH;
00538 alpha_size = 1;
00539 }
00540
00541 if ( db_size < 0 )
00542 {
00543 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_WARNING_LVL)
00544 << "WARNING: Depth buffer size was negative, set to: " << db_size
00545 << ". Setting to 1.\n" << vprDEBUG_FLUSH;
00546 db_size = 1;
00547 }
00548 }
00549
00550 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00551 << "Frame buffer visual settings for " << mVrjDisplay->getName()
00552 << ": R:" << red_size << " G:" << green_size << " B:" << blue_size
00553 << " A:" << alpha_size << " DB:" << db_size << std::endl
00554 << vprDEBUG_FLUSH;
00555
00556 ::XVisualInfo *vi;
00557 std::vector<int> viattrib;
00558 viattrib.push_back(GLX_DOUBLEBUFFER);
00559 viattrib.push_back(GLX_RGBA);
00560 viattrib.push_back(GLX_DEPTH_SIZE); viattrib.push_back(db_size);
00561 viattrib.push_back(GLX_RED_SIZE); viattrib.push_back(red_size);
00562 viattrib.push_back(GLX_GREEN_SIZE); viattrib.push_back(green_size);
00563 viattrib.push_back(GLX_BLUE_SIZE); viattrib.push_back(blue_size);
00564 viattrib.push_back(GLX_ALPHA_SIZE); viattrib.push_back(alpha_size);
00565 const unsigned int AlphaAttribIndex = 11;
00566
00567
00568 #ifdef GLX_SAMPLES_SGIS
00569
00570
00571 const unsigned int fsaa_attrib_index = viattrib.size();
00572
00573 if ( want_fsaa )
00574 {
00575 viattrib.push_back(GLX_SAMPLES_SGIS); viattrib.push_back(1);
00576 viattrib.push_back(GLX_SAMPLE_BUFFERS_SGIS); viattrib.push_back(1);
00577 }
00578 #else
00579 if ( want_fsaa )
00580 {
00581 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CONFIG_LVL)
00582 << "WARNING: Full-screen anti-aliasing is not available\n"
00583 << vprDEBUG_FLUSH;
00584 }
00585 #endif
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 if ( !glXQueryExtension(display, NULL, NULL) )
00598 {
00599 vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
00600 << clrOutNORM(clrRED, "ERROR:") << " X Display '" << mXDisplayName
00601 << "' doesn't support GLX.\n" << vprDEBUG_FLUSH;
00602 return NULL;
00603 }
00604
00605 if ( mVrjDisplay->isStereoRequested() )
00606 {
00607 viattrib.push_back(GLX_STEREO);
00608 in_stereo = true;
00609 }
00610 else
00611 {
00612 in_stereo = false;
00613 }
00614
00615
00616 viattrib.push_back(None);
00617
00618
00619 if ( (vi = glXChooseVisual(display, screen, &viattrib[0])) != NULL )
00620 {
00621 return vi;
00622 }
00623
00624
00625 if ( mVrjDisplay->isStereoRequested() )
00626 {
00627 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CRITICAL_LVL)
00628 << "WARNING: Display process for '" << mXDisplayName
00629 << "' couldn't get display in stereo - trying mono.\n"
00630 << vprDEBUG_FLUSH;
00631 in_stereo = false;
00632 viattrib[viattrib.size() - 1] = GLX_USE_GL;
00633
00634 if ( (vi = glXChooseVisual(display, screen, &viattrib[0])) != NULL )
00635 {
00636 return vi;
00637 }
00638 }
00639
00640
00641 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CRITICAL_LVL)
00642 << "WARNING: Display process for '" << mXDisplayName
00643 << "' couldn't get display with alpha channel - trying without.\n"
00644 << vprDEBUG_FLUSH;
00645 viattrib[AlphaAttribIndex] = 0;
00646
00647 if ( (vi = glXChooseVisual(display, screen, &viattrib[0])) != NULL )
00648 {
00649 return vi;
00650 }
00651
00652 #ifdef GLX_SAMPLES_SGIS
00653
00654
00655 if ( want_fsaa )
00656 {
00657 vprDEBUG(vrjDBG_DRAW_MGR, vprDBG_CRITICAL_LVL)
00658 << "WARNING: Display process for '" << mXDisplayName
00659 << "' couldn't get FSAA - trying without it.\n" << vprDEBUG_FLUSH;
00660
00661
00662
00663
00664
00665 viattrib[fsaa_attrib_index] = None;
00666
00667 if ( (vi = glXChooseVisual(display, screen, &viattrib[0])) != NULL )
00668 {
00669 return vi;
00670 }
00671 }
00672 #endif
00673
00674
00675 return NULL;
00676 }
00677
00684 int GlWindowXWin::EventIsMapNotify(::Display* display, ::XEvent* e,
00685 ::XPointer window)
00686 {
00687 boost::ignore_unused_variable_warning(display);
00688 return((e->type == MapNotify) && (e->xmap.window == (Window)window));
00689 }
00690
00691 void GlWindowXWin::processEvent(XEvent event)
00692 {
00693 switch ( event.type )
00694 {
00695 case ConfigureNotify:
00696
00697 updateOriginSize(vrj::GlWindow::origin_x, vrj::GlWindow::origin_y,
00698 event.xconfigure.width, event.xconfigure.height);
00699 vrj::GlWindow::setDirtyViewport(true);
00700 break;
00701
00702 default:
00703 break;
00704 }
00705 }
00706
00707 }