00001
00002
00003
00004
00005
00006
00007
00008
00009
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
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 ClassImp(TGLWidget);
00067
00068
00069
00070
00071
00072
00073 TGLWidget* TGLWidget::CreateDummy()
00074 {
00075
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
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
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
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
00160
00161 #ifndef WIN32
00162 XFree(fInnerData.second);
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
00183 }
00184
00185
00186 void TGLWidget::PaintGL()
00187 {
00188
00189 }
00190
00191
00192 Bool_t TGLWidget::MakeCurrent()
00193 {
00194
00195 return fGLContext->MakeCurrent();
00196 }
00197
00198
00199 Bool_t TGLWidget::ClearCurrent()
00200 {
00201
00202 return fGLContext->ClearCurrent();
00203 }
00204
00205
00206 void TGLWidget::SwapBuffers()
00207 {
00208
00209 fGLContext->SwapBuffers();
00210 }
00211
00212
00213 const TGLContext *TGLWidget::GetContext()const
00214 {
00215
00216 return fGLContext;
00217 }
00218
00219
00220 const TGLFormat *TGLWidget::GetPixelFormat()const
00221 {
00222
00223 return &fGLFormat;
00224 }
00225
00226
00227 std::pair<void *, void *> TGLWidget::GetInnerData()const
00228 {
00229
00230 return fInnerData;
00231 }
00232
00233
00234 void TGLWidget::AddContext(TGLContext *ctx)
00235 {
00236
00237 fValidContexts.insert(ctx);
00238 }
00239
00240
00241 void TGLWidget::RemoveContext(TGLContext *ctx)
00242 {
00243
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
00253 vp[0] = 0;
00254 vp[1] = 0;
00255 vp[2] = GetWidth();
00256 vp[3] = GetHeight();
00257 }
00258
00259
00260
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& ,
00321 UInt_t width, UInt_t height,
00322 std::pair<void *, void *>& innerData)
00323 {
00324
00325
00326
00327
00328
00329
00330
00331
00332
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
00345
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
00441
00442
00443
00444
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);
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
00485
00486 }
00487
00488
00489 #endif
00490
00491
00492
00493
00494
00495
00496
00497
00498 void TGLWidget::SetEventHandler(TGEventHandler *eh)
00499 {
00500
00501 fEventHandler = eh;
00502 }
00503
00504
00505 Bool_t TGLWidget::HandleCrossing(Event_t *ev)
00506 {
00507
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
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
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
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
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
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
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
00607
00608
00609
00610
00611 if (fEventHandler)
00612 return fEventHandler->Repaint();
00613 }