TGLWidget.cxx

Go to the documentation of this file.
00001 // @(#)root/gl:$Id: TGLWidget.cxx 36675 2010-11-15 20:33:58Z matevz $
00002 // Author:  Timur Pocheptsov, Jun 2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include <stdexcept>
00013 #include <vector>
00014 
00015 #include "TVirtualX.h"
00016 #include "TGClient.h"
00017 #include "TError.h"
00018 #include "TROOT.h"
00019 
00020 #include "TGLWidget.h"
00021 #include "TGLIncludes.h"
00022 #include "TGLWSIncludes.h"
00023 #include "TGLUtil.h"
00024 
00025 #include "TGLEventHandler.h"
00026 
00027 /******************************************************************************/
00028 // TGLWidget
00029 /******************************************************************************/
00030 
00031 //______________________________________________________________________________
00032 //
00033 // GL window with context. _Must_ _have_ a parent window
00034 // (the 'parent' parameter of ctors). The current version inherits
00035 // TGCanvas (I'm not sure about future versions), probably, in future
00036 // multiple inheritance will be added - the second
00037 // base class will be TGLPaintDevice or something like this.
00038 //
00039 // Usage:
00040 // - Simply create TGLWidget as an embedded widget, and
00041 //   connect your slots to signals you need: HandleExpose, HandleConfigureNotify, etc.
00042 //   In your slots you can use gl API directly - under Win32 TGLWidget switches
00043 //   between threads internally (look TGLPShapeObjEditor for such usage).
00044 // - You can write your own class, derived from TGLWidget, with PaintGL and InitGL
00045 //   overriden.
00046 //
00047 // Resources (and invariants):
00048 // -fContainer (TGLWidgetContainer) - controlled by std::auto_ptr
00049 // -fWindowIndex - controlled manually (see CreateWidget and dtor)
00050 // -fGLContext - controlled manually (see CreateWidget and dtor)
00051 // -visual info for X11 version, controlled manually (see CreateGLContainer and dtor)
00052 //
00053 // Exceptions:
00054 // -can be thrown only during construction.
00055 // -under win32 class does not throw itself (but some internal operations can throw)
00056 // -under X11 can throw std::runtime_error (from CreateGLContext).
00057 // -In case of exceptions resources will be freed.
00058 //
00059 // TGLWidget object is immutable as far as it was created.
00060 //
00061 // Boolean parameter defines, if you want to grab user's input or not.
00062 // By default you want, but for example when not - see TGLPShapeObjEditor.
00063 //
00064 // Non-copyable.
00065 
00066 ClassImp(TGLWidget);
00067 
00068 //==============================================================================
00069 // TGLWidget - system-independent methods
00070 //==============================================================================
00071 
00072 //______________________________________________________________________________
00073 TGLWidget* TGLWidget::CreateDummy()
00074 {
00075    // Static constructor for creating widget with default pixel format.
00076 
00077    TGLFormat format(TGLFormat::kNone);
00078 
00079    return Create(format, gClient->GetDefaultRoot(), kFALSE, kFALSE, 0, 1, 1);
00080 }
00081 
00082 //______________________________________________________________________________
00083 TGLWidget* TGLWidget::Create(const TGWindow* parent, Bool_t selectInput,
00084               Bool_t shareDefault, const TGLPaintDevice *shareDevice,
00085               UInt_t width, UInt_t height)
00086 {
00087    // Static constructor for creating widget with default pixel format.
00088 
00089    TGLFormat format;
00090 
00091    return Create(format, parent, selectInput, shareDefault, shareDevice,
00092                  width, height);
00093 }
00094 
00095 //______________________________________________________________________________
00096 TGLWidget* TGLWidget::Create(const TGLFormat &format,
00097              const TGWindow* parent, Bool_t selectInput,
00098              Bool_t shareDefault, const TGLPaintDevice *shareDevice,
00099              UInt_t width, UInt_t height)
00100 {
00101    // Static constructor for creating widget with given pixel format.
00102 
00103    std::pair<void *, void *> innerData;
00104 
00105    Window_t wid = CreateWindow(parent, format, width, height, innerData);
00106 
00107    TGLWidget* glw = new TGLWidget(wid, parent, selectInput);
00108 
00109 #ifdef WIN32
00110    glw->fWindowIndex = (Int_t) innerData.second;
00111 #else
00112    glw->fWindowIndex = gVirtualX->AddWindow(wid, width, height);
00113    glw->fInnerData   = innerData;
00114 #endif
00115    glw->fGLFormat  = format;
00116 
00117    try
00118    {
00119       glw->SetFormat();
00120       glw->fGLContext = new TGLContext
00121          (glw, shareDefault, shareDevice && !shareDefault ? shareDevice->GetContext() : 0);
00122    }
00123    catch (const std::exception &)
00124    {
00125       delete glw;
00126       throw;
00127    }
00128 
00129    glw->fFromInit = kFALSE;
00130 
00131    return glw;
00132 }
00133 
00134 //______________________________________________________________________________
00135 TGLWidget::TGLWidget(Window_t glw, const TGWindow* p, Bool_t selectInput)
00136    : TGFrame(gClient, glw, p),
00137      fGLContext(0),
00138      fWindowIndex(-1),
00139      fGLFormat(TGLFormat::kNone),
00140      fFromInit(kTRUE),
00141      fEventHandler(0)
00142 {
00143    // Creates widget with default pixel format.
00144 
00145    if (selectInput)
00146    {
00147       gVirtualX->GrabButton(GetId(), kAnyButton, kAnyModifier,
00148                             kButtonPressMask | kButtonReleaseMask, kNone, kNone);
00149       gVirtualX->SelectInput(GetId(), kKeyPressMask | kKeyReleaseMask | kExposureMask |
00150                              kPointerMotionMask | kStructureNotifyMask | kFocusChangeMask |
00151                              kEnterWindowMask | kLeaveWindowMask);
00152       gVirtualX->SetInputFocus(GetId());
00153    }
00154 }
00155 
00156 //______________________________________________________________________________
00157 TGLWidget::~TGLWidget()
00158 {
00159    //Destructor. Deletes window ???? and XVisualInfo
00160 
00161 #ifndef WIN32
00162    XFree(fInnerData.second);//free XVisualInfo
00163 #endif
00164    if (fValidContexts.size() > 1u) {
00165       Warning("~TGLWidget", "There are some gl-contexts connected to this gl device"
00166                             "which have longer lifetime than lifetime of gl-device");
00167    }
00168 
00169    std::set<TGLContext *>::iterator it = fValidContexts.begin();
00170    for (; it != fValidContexts.end(); ++it) {
00171       (*it)->Release();
00172    }
00173    delete fGLContext;
00174 
00175    gVirtualX->SelectWindow(fWindowIndex);
00176    gVirtualX->CloseWindow();
00177 }
00178 
00179 //______________________________________________________________________________
00180 void TGLWidget::InitGL()
00181 {
00182    //Call glEnable(... in overrider of InitGL.
00183 }
00184 
00185 //______________________________________________________________________________
00186 void TGLWidget::PaintGL()
00187 {
00188    //Do actual drawing in overrider of PaintGL.
00189 }
00190 
00191 //______________________________________________________________________________
00192 Bool_t TGLWidget::MakeCurrent()
00193 {
00194    //Make the gl-context current.
00195    return fGLContext->MakeCurrent();
00196 }
00197 
00198 //______________________________________________________________________________
00199 Bool_t TGLWidget::ClearCurrent()
00200 {
00201    //Clear the current gl-context.
00202    return fGLContext->ClearCurrent();
00203 }
00204 
00205 //______________________________________________________________________________
00206 void TGLWidget::SwapBuffers()
00207 {
00208    //Swap buffers.
00209    fGLContext->SwapBuffers();
00210 }
00211 
00212 //______________________________________________________________________________
00213 const TGLContext *TGLWidget::GetContext()const
00214 {
00215    //Get gl context.
00216    return fGLContext;
00217 }
00218 
00219 //______________________________________________________________________________
00220 const TGLFormat *TGLWidget::GetPixelFormat()const
00221 {
00222    //Pixel format.
00223    return &fGLFormat;
00224 }
00225 
00226 //______________________________________________________________________________
00227 std::pair<void *, void *> TGLWidget::GetInnerData()const
00228 {
00229    //Dpy*, XVisualInfo *
00230    return fInnerData;
00231 }
00232 
00233 //______________________________________________________________________________
00234 void TGLWidget::AddContext(TGLContext *ctx)
00235 {
00236    //Register gl-context created for this window.
00237    fValidContexts.insert(ctx);
00238 }
00239 
00240 //______________________________________________________________________________
00241 void TGLWidget::RemoveContext(TGLContext *ctx)
00242 {
00243    //Remove context (no real deletion, done by TGLContex dtor).
00244    std::set<TGLContext *>::iterator it = fValidContexts.find(ctx);
00245    if (it != fValidContexts.end())
00246       fValidContexts.erase(it);
00247 }
00248 
00249 //______________________________________________________________________________
00250 void TGLWidget::ExtractViewport(Int_t *vp)const
00251 {
00252    //For camera.
00253    vp[0] = 0;
00254    vp[1] = 0;
00255    vp[2] = GetWidth();
00256    vp[3] = GetHeight();
00257 }
00258 
00259 //==============================================================================
00260 // System specific methods and helper functions
00261 //==============================================================================
00262 
00263 //==============================================================================
00264 #ifdef WIN32
00265 //==============================================================================
00266 
00267 namespace {
00268 
00269    struct LayoutCompatible_t {
00270       void          *fDummy0;
00271       void          *fDummy1;
00272       HWND          *fPHwnd;
00273       unsigned char  fDummy2;
00274       unsigned       fDummy3;
00275       unsigned short fDummy4;
00276       unsigned short fDummy5;
00277       void          *fDummy6;
00278       unsigned       fDummy7:2;
00279    };
00280 
00281    void fill_pfd(PIXELFORMATDESCRIPTOR *pfd, const TGLFormat &request)
00282    {
00283       pfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
00284       pfd->nVersion = 1;
00285       pfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
00286       if (request.IsDoubleBuffered())
00287          pfd->dwFlags |= PFD_DOUBLEBUFFER;
00288       pfd->iPixelType = PFD_TYPE_RGBA;
00289       pfd->cColorBits = 24;
00290       if (UInt_t acc = request.GetAccumSize())
00291          pfd->cAccumBits = acc;
00292       if (UInt_t depth = request.GetDepthSize())
00293          pfd->cDepthBits = depth;
00294       if (UInt_t stencil = request.GetStencilSize())
00295          pfd->cStencilBits = stencil;
00296    }
00297 
00298    void check_pixel_format(Int_t pixIndex, HDC hDC, TGLFormat &request)
00299    {
00300       PIXELFORMATDESCRIPTOR pfd = {};
00301 
00302       if (!DescribePixelFormat(hDC, pixIndex, sizeof pfd, &pfd)) {
00303          Warning("TGLContext::SetContext", "DescribePixelFormat failed");
00304          return;
00305       }
00306 
00307       if (pfd.cAccumBits)
00308          request.SetAccumSize(pfd.cAccumBits);
00309 
00310       if (pfd.cDepthBits)
00311          request.SetDepthSize(pfd.cDepthBits);
00312 
00313       if (pfd.cStencilBits)
00314          request.SetStencilSize(pfd.cStencilBits);
00315    }
00316 
00317 }
00318 
00319 //______________________________________________________________________________
00320 Window_t TGLWidget::CreateWindow(const TGWindow* parent, const TGLFormat& /*format*/,
00321                                  UInt_t width, UInt_t  height,
00322                                  std::pair<void *, void *>& innerData)
00323 {
00324    // CreateWidget.
00325    // Static function called prior to widget construction,
00326    // I've extracted this code from ctors to make WIN32/X11
00327    // separation simpler and because of gInterpreter usage.
00328    // new, TGLContext can throw
00329    // std::bad_alloc and std::runtime_error. Before try block, the only
00330    // resource allocated is pointed by fWindowIndex (InitWindow cannot throw).
00331    // In try block (and after successful constraction)
00332    // resources are controlled by std::auto_ptrs and dtor.
00333 
00334    Int_t widx = gVirtualX->InitWindow((ULong_t)parent->GetId());
00335    innerData.second = (void*) widx;
00336    Window_t win = gVirtualX->GetWindowID(widx);
00337    gVirtualX->ResizeWindow(win, width, height);
00338    return win;
00339 }
00340 
00341 //______________________________________________________________________________
00342 void TGLWidget::SetFormat()
00343 {
00344    // Set pixel format.
00345    // Resource - hDC, owned and freed by guard object.
00346 
00347    if (!fFromInit) {
00348       Error("TGLWidget::SetFormat", "Sorry, you should not call this function");
00349       return;
00350    }
00351    if (!gVirtualX->IsCmdThread())
00352       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->SetFormat()", this));
00353 
00354    LayoutCompatible_t *trick =
00355       reinterpret_cast<LayoutCompatible_t *>(GetId());
00356    HWND hWND = *trick->fPHwnd;
00357    HDC  hDC  = GetWindowDC(hWND);
00358 
00359    if (!hDC) {
00360       Error("TGLWidget::SetFormat", "GetWindowDC failed");
00361       throw std::runtime_error("GetWindowDC failed");
00362    }
00363 
00364    const Rgl::TGuardBase &dcGuard = Rgl::make_guard(ReleaseDC, hWND, hDC);
00365    PIXELFORMATDESCRIPTOR pfd = {};
00366    fill_pfd(&pfd, fGLFormat);
00367 
00368    if (const Int_t pixIndex = ChoosePixelFormat(hDC, &pfd)) {
00369       check_pixel_format(pixIndex, hDC, fGLFormat);
00370 
00371       if (!SetPixelFormat(hDC, pixIndex, &pfd)) {
00372          Error("TGLWidget::SetFormat", "SetPixelFormat failed");
00373          throw std::runtime_error("SetPixelFormat failed");
00374       }
00375    } else {
00376       Error("TGLWidget::SetFormat", "ChoosePixelFormat failed");
00377       throw std::runtime_error("ChoosePixelFormat failed");
00378    }
00379 }
00380 
00381 //==============================================================================
00382 #else // Non WIN32
00383 //==============================================================================
00384 
00385 namespace
00386 {
00387    void fill_format(std::vector<Int_t> &format, const TGLFormat &request)
00388    {
00389       format.push_back(GLX_RGBA);
00390       format.push_back(GLX_RED_SIZE);
00391       format.push_back(1);
00392       format.push_back(GLX_GREEN_SIZE);
00393       format.push_back(1);
00394       format.push_back(GLX_BLUE_SIZE);
00395       format.push_back(1);
00396 
00397       if (request.IsDoubleBuffered())
00398          format.push_back(GLX_DOUBLEBUFFER);
00399 
00400       if (request.HasDepth()) {
00401          format.push_back(GLX_DEPTH_SIZE);
00402          format.push_back(request.GetDepthSize());
00403       }
00404 
00405       if (request.HasStencil()) {
00406          format.push_back(GLX_STENCIL_SIZE);
00407          format.push_back(request.GetStencilSize());
00408       }
00409 
00410       if (request.HasAccumBuffer()) {
00411          format.push_back(GLX_ACCUM_RED_SIZE);
00412          format.push_back(1);
00413          format.push_back(GLX_ACCUM_GREEN_SIZE);
00414          format.push_back(1);
00415          format.push_back(GLX_ACCUM_BLUE_SIZE);
00416          format.push_back(1);
00417       }
00418 
00419       if (request.IsStereo()) {
00420          format.push_back(GLX_STEREO);
00421       }
00422 
00423       if (request.HasMultiSampling())
00424       {
00425          format.push_back(GLX_SAMPLE_BUFFERS_ARB);
00426          format.push_back(1);
00427          format.push_back(GLX_SAMPLES_ARB);
00428          format.push_back(request.GetSamples());
00429       }
00430 
00431       format.push_back(None);
00432    }
00433 }
00434 
00435 //______________________________________________________________________________
00436 Window_t TGLWidget::CreateWindow(const TGWindow* parent, const TGLFormat &format,
00437                                  UInt_t width, UInt_t height,
00438                                  std::pair<void *, void *>& innerData)
00439 {
00440    // CreateWidget - X11 version.
00441    // Static function called prior to construction.
00442    // Can throw std::bad_alloc and std::runtime_error.
00443    // This version is bad - I do not check the results of
00444    // X11 calls.
00445 
00446    std::vector<Int_t> glxfmt;
00447    fill_format(glxfmt, format);
00448 
00449    Display *dpy = reinterpret_cast<Display *>(gVirtualX->GetDisplay());
00450    if (!dpy) {
00451       ::Error("TGLWidget::CreateWindow", "Display is not set!");
00452       throw std::runtime_error("Display is not set!");
00453    }
00454    XVisualInfo *visInfo = glXChooseVisual(dpy, DefaultScreen(dpy), &glxfmt[0]);
00455 
00456    if (!visInfo) {
00457       ::Error("TGLWidget::CreateWindow", "No good OpenGL visual found!");
00458       throw std::runtime_error("No good OpenGL visual found!");
00459    }
00460 
00461    Window_t winID = parent->GetId();
00462 
00463    XSetWindowAttributes attr;
00464    attr.colormap         = XCreateColormap(dpy, winID, visInfo->visual, AllocNone); // Can fail?
00465    attr.background_pixel = 0;
00466    attr.event_mask       = NoEventMask;
00467    attr.backing_store    = Always;
00468    attr.bit_gravity      = NorthWestGravity;
00469 
00470    ULong_t mask = CWBackPixel | CWColormap | CWEventMask | CWBackingStore | CWBitGravity;
00471    Window glWin = XCreateWindow(dpy, winID, 0, 0, width, height, 0,
00472                                 visInfo->depth,
00473                                 InputOutput, visInfo->visual, mask, &attr);
00474 
00475    innerData.first  = dpy;
00476    innerData.second = visInfo;
00477 
00478    return glWin;
00479 }
00480 
00481 //______________________________________________________________________________
00482 void TGLWidget::SetFormat()
00483 {
00484    // Set pixel format.
00485    // Empty version for X11.
00486 }
00487 
00488 //==============================================================================
00489 #endif
00490 //==============================================================================
00491 
00492 
00493 //==============================================================================
00494 // Event handling
00495 //==============================================================================
00496 
00497 //______________________________________________________________________________
00498 void TGLWidget::SetEventHandler(TGEventHandler *eh)
00499 {
00500    //Set event-handler. All events are passed to this object.
00501    fEventHandler = eh;
00502 }
00503 
00504 //______________________________________________________________________________
00505 Bool_t TGLWidget::HandleCrossing(Event_t *ev)
00506 {
00507    // Handle mouse crossing event.
00508    if (!gVirtualX->IsCmdThread()) {
00509       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleCrossing((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00510       return kTRUE;
00511    }
00512    if ((ev->fType == kEnterNotify) &&
00513        (!gVirtualX->InheritsFrom("TGX11")) &&
00514        (gVirtualX->GetInputFocus() != GetId())) {
00515       gVirtualX->SetInputFocus(GetId());
00516    }
00517    if (fEventHandler)
00518       return fEventHandler->HandleCrossing(ev);
00519    return kFALSE;
00520 }
00521 
00522 //______________________________________________________________________________
00523 Bool_t TGLWidget::HandleButton(Event_t *ev)
00524 {
00525    //Delegate call to the owner.
00526    if (!gVirtualX->IsCmdThread()) {
00527       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleButton((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00528       return kTRUE;
00529    }
00530    if (fEventHandler)
00531       return fEventHandler->HandleButton(ev);
00532    return kFALSE;
00533 }
00534 
00535 //______________________________________________________________________________
00536 Bool_t TGLWidget::HandleDoubleClick(Event_t *ev)
00537 {
00538    //Delegate call to the owner.
00539    if (!gVirtualX->IsCmdThread()) {
00540       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleDoubleClick((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00541       return kTRUE;
00542    }
00543    if (fEventHandler)
00544       return fEventHandler->HandleDoubleClick(ev);
00545    return kFALSE;
00546 }
00547 
00548 //______________________________________________________________________________
00549 Bool_t TGLWidget::HandleConfigureNotify(Event_t *ev)
00550 {
00551    //Delegate call to the owner.
00552    if (!gVirtualX->IsCmdThread()) {
00553       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleConfigureNotify((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00554       return kTRUE;
00555    }
00556    if (fEventHandler && fEventHandler->HandleConfigureNotify(ev))
00557    {
00558       TGFrame::HandleConfigureNotify(ev);
00559       return kTRUE;
00560    }
00561    return kFALSE;
00562 }
00563 
00564 //______________________________________________________________________________
00565 Bool_t TGLWidget::HandleFocusChange(Event_t *ev)
00566 {
00567    //Delegate call to the owner.
00568    if (!gVirtualX->IsCmdThread()) {
00569       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleFocusChange((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00570       return kTRUE;
00571    }
00572    if (fEventHandler)
00573       return fEventHandler->HandleFocusChange(ev);
00574    return kFALSE;
00575 }
00576 
00577 //______________________________________________________________________________
00578 Bool_t TGLWidget::HandleKey(Event_t *ev)
00579 {
00580    //Delegate call to the owner.
00581    if (!gVirtualX->IsCmdThread()) {
00582       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleKey((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00583       return kTRUE;
00584    }
00585    if (fEventHandler)
00586       return fEventHandler->HandleKey(ev);
00587    return kFALSE;
00588 }
00589 
00590 //______________________________________________________________________________
00591 Bool_t TGLWidget::HandleMotion(Event_t *ev)
00592 {
00593    //Delegate call to the owner.
00594    if (!gVirtualX->IsCmdThread()) {
00595       gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->HandleMotion((Event_t *)0x%lx)", (ULong_t)this, (ULong_t)ev));
00596       return kTRUE;
00597    }
00598    if (fEventHandler)
00599       return fEventHandler->HandleMotion(ev);
00600    return kFALSE;
00601 }
00602 
00603 //______________________________________________________________________________
00604 void TGLWidget::DoRedraw()
00605 {
00606    //Delegate call to the owner.
00607 //   if (!gVirtualX->IsCmdThread()) {
00608 //      gROOT->ProcessLineFast(Form("((TGLWidget *)0x%lx)->DoRedraw()", this));
00609 //      return;
00610 //   }
00611    if (fEventHandler)
00612       return fEventHandler->Repaint();
00613 }

Generated on Tue Jul 5 14:18:10 2011 for ROOT_528-00b_version by  doxygen 1.5.1