Line data Source code
1 :
2 : /* Copyright (c) 2009-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Maxim Makhinya
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "window.h"
21 :
22 : #ifdef EQUALIZER_USE_QT5WIDGETS
23 : #include "../qt/window.h" // must be included before any header defining Bool
24 : #endif
25 :
26 : #include "eventHandler.h"
27 : #include "messagePump.h"
28 :
29 : #include "../error.h"
30 : #include "../gl.h"
31 : #include "../global.h"
32 :
33 : #include <co/objectOCommand.h>
34 :
35 : namespace eq
36 : {
37 : namespace glx
38 : {
39 : namespace detail
40 : {
41 : #define getIAttribute(attr) getIAttribute(WindowSettings::attr)
42 :
43 : class Window
44 : {
45 : public:
46 3 : Window(Display* xDisplay_, const GLXEWContext* glxewContext_,
47 : MessagePump* messagePump_)
48 3 : : xDisplay(xDisplay_)
49 : , xDrawable(0)
50 : , glXContext(0)
51 : , glXNVSwapGroup(0)
52 : , glXEventHandler(0)
53 : , glxewContext(glxewContext_)
54 3 : , messagePump(messagePump_)
55 : {
56 3 : }
57 :
58 : /** The display connection (maintained by GLXPipe) */
59 : Display* xDisplay;
60 : /** The X11 drawable ID of the window. */
61 : XID xDrawable;
62 : /** The glX rendering context. */
63 : GLXContext glXContext;
64 : /** The currently joined swap group. */
65 : uint32_t glXNVSwapGroup;
66 :
67 : /** The event handler. */
68 : EventHandler* glXEventHandler;
69 :
70 : /** The glX extension pointer table. */
71 : const GLXEWContext* glxewContext;
72 :
73 : MessagePump* const messagePump;
74 : };
75 : }
76 :
77 3 : Window::Window(NotifierInterface& parent, const WindowSettings& settings,
78 : Display* xDisplay, const GLXEWContext* glxewContext,
79 3 : MessagePump* messagePump)
80 : : WindowIF(parent, settings)
81 3 : , _impl(new detail::Window(xDisplay, glxewContext, messagePump))
82 : {
83 3 : }
84 :
85 9 : Window::~Window()
86 : {
87 3 : delete _impl;
88 6 : }
89 :
90 : //---------------------------------------------------------------------------
91 : // GLX init
92 : //---------------------------------------------------------------------------
93 : namespace
94 : {
95 1 : static Bool WaitForNotify(Display*, XEvent* e, char* arg)
96 : {
97 1 : return (e->type == MapNotify) && (e->xmap.window == (::Window)arg);
98 : }
99 : }
100 :
101 3 : bool Window::configInit()
102 : {
103 3 : GLXFBConfig* fbConfig = chooseGLXFBConfig();
104 3 : if (!fbConfig)
105 : {
106 0 : sendError(ERROR_SYSTEMWINDOW_PIXELFORMAT_NOTFOUND);
107 0 : return false;
108 : }
109 :
110 3 : GLXContext context = createGLXContext(fbConfig);
111 3 : setGLXContext(context);
112 3 : if (!context)
113 : {
114 0 : XFree(fbConfig);
115 0 : return false;
116 : }
117 :
118 3 : bool success = configInitGLXDrawable(fbConfig);
119 3 : XFree(fbConfig);
120 :
121 3 : if (!success || !_impl->xDrawable)
122 : {
123 0 : sendError(ERROR_GLXWINDOW_NO_DRAWABLE);
124 0 : return false;
125 : }
126 :
127 3 : makeCurrent();
128 3 : initGLEW();
129 3 : _initSwapSync();
130 3 : if (getIAttribute(IATTR_HINT_DRAWABLE) == FBO)
131 1 : success = configInitFBO();
132 :
133 3 : return success;
134 : }
135 :
136 3 : GLXFBConfig* Window::chooseGLXFBConfig()
137 : {
138 3 : if (!_impl->xDisplay)
139 : {
140 0 : sendError(ERROR_GLXWINDOW_NO_DISPLAY);
141 0 : return 0;
142 : }
143 3 : if (!GLXEW_VERSION_1_3 && !GLXEW_SGIX_fbconfig)
144 : {
145 0 : sendError(ERROR_GLXWINDOW_FBCONFIG_REQUIRED);
146 0 : return 0;
147 : }
148 :
149 : // build attribute list
150 6 : std::vector<int> attributes;
151 3 : const int32_t drawableHint = getIAttribute(IATTR_HINT_DRAWABLE);
152 3 : switch (drawableHint)
153 : {
154 : default:
155 0 : LBWARN << "Unknown drawable type " << drawableHint << ", using window"
156 0 : << std::endl;
157 : // no break;
158 : case UNDEFINED:
159 : case OFF: // needs fbConfig with visual for dummy window
160 : case FBO: // No typo - FBO needs fbConfig with visual for dummy window
161 : case WINDOW:
162 3 : attributes.push_back(GLX_X_RENDERABLE);
163 3 : attributes.push_back(True);
164 : }
165 :
166 3 : int colorSize = getIAttribute(IATTR_PLANES_COLOR);
167 3 : if (colorSize != OFF)
168 : {
169 3 : if (drawableHint == FBO || drawableHint == OFF)
170 2 : colorSize = 8; // Create FBO dummy window with 8bpp
171 : else
172 1 : switch (colorSize)
173 : {
174 : case RGBA16F:
175 : case RGBA32F:
176 0 : if (!GLXEW_ARB_fbconfig_float)
177 : {
178 0 : sendError(ERROR_SYSTEMWINDOW_ARB_FLOAT_FB_REQUIRED);
179 0 : return 0;
180 : }
181 0 : attributes.push_back(GLX_RENDER_TYPE);
182 0 : attributes.push_back(GLX_RGBA_FLOAT_BIT);
183 0 : colorSize = colorSize == RGBA16F ? 16 : 32;
184 0 : break;
185 :
186 : case AUTO:
187 : case ON:
188 1 : colorSize = 8;
189 1 : break;
190 : default:
191 0 : break;
192 : }
193 :
194 3 : LBASSERT(colorSize > 0);
195 3 : attributes.push_back(GLX_RED_SIZE);
196 3 : attributes.push_back(colorSize);
197 3 : attributes.push_back(GLX_GREEN_SIZE);
198 3 : attributes.push_back(colorSize);
199 3 : attributes.push_back(GLX_BLUE_SIZE);
200 3 : attributes.push_back(colorSize);
201 :
202 3 : const int alphaSize = getIAttribute(IATTR_PLANES_ALPHA);
203 3 : switch (alphaSize)
204 : {
205 : case AUTO:
206 : case UNDEFINED:
207 : case ON:
208 3 : attributes.push_back(GLX_ALPHA_SIZE);
209 3 : attributes.push_back(colorSize);
210 3 : break;
211 :
212 : case OFF:
213 0 : break;
214 :
215 : default:
216 0 : LBASSERT(alphaSize > 0);
217 0 : attributes.push_back(GLX_ALPHA_SIZE);
218 0 : attributes.push_back(alphaSize > 0 ? alphaSize : colorSize);
219 : }
220 : }
221 3 : const int depthSize = getIAttribute(IATTR_PLANES_DEPTH);
222 3 : if (depthSize > 0 || depthSize == AUTO)
223 : {
224 3 : attributes.push_back(GLX_DEPTH_SIZE);
225 3 : attributes.push_back(depthSize > 0 ? depthSize : 1);
226 : }
227 3 : const int stencilSize = getIAttribute(IATTR_PLANES_STENCIL);
228 3 : if (stencilSize > 0 || stencilSize == AUTO)
229 : {
230 3 : attributes.push_back(GLX_STENCIL_SIZE);
231 3 : attributes.push_back(stencilSize > 0 ? stencilSize : 1);
232 : }
233 3 : const int accumSize = getIAttribute(IATTR_PLANES_ACCUM);
234 3 : const int accumAlpha = getIAttribute(IATTR_PLANES_ACCUM_ALPHA);
235 3 : if (accumSize >= 0)
236 : {
237 0 : attributes.push_back(GLX_ACCUM_RED_SIZE);
238 0 : attributes.push_back(accumSize);
239 0 : attributes.push_back(GLX_ACCUM_GREEN_SIZE);
240 0 : attributes.push_back(accumSize);
241 0 : attributes.push_back(GLX_ACCUM_BLUE_SIZE);
242 0 : attributes.push_back(accumSize);
243 0 : attributes.push_back(GLX_ACCUM_ALPHA_SIZE);
244 0 : attributes.push_back(accumAlpha >= 0 ? accumAlpha : accumSize);
245 : }
246 3 : else if (accumAlpha >= 0)
247 : {
248 0 : attributes.push_back(GLX_ACCUM_ALPHA_SIZE);
249 0 : attributes.push_back(accumAlpha);
250 : }
251 :
252 3 : const int samplesSize = getIAttribute(IATTR_PLANES_SAMPLES);
253 3 : if (samplesSize >= 0 && drawableHint != FBO)
254 : {
255 0 : attributes.push_back(GLX_SAMPLE_BUFFERS);
256 0 : attributes.push_back(1);
257 0 : attributes.push_back(GLX_SAMPLES);
258 0 : attributes.push_back(samplesSize);
259 : }
260 :
261 : #ifdef Darwin
262 : // WAR: glDrawBuffer( GL_BACK ) renders only to the left back buffer on a
263 : // stereo visual on Darwin which creates ugly flickering on mono configs
264 : if (getIAttribute(IATTR_HINT_STEREO) == ON)
265 : {
266 : attributes.push_back(GLX_STEREO);
267 : attributes.push_back(true);
268 : }
269 : #else
270 7 : if (getIAttribute(IATTR_HINT_STEREO) == ON ||
271 6 : (getIAttribute(IATTR_HINT_STEREO) == AUTO &&
272 3 : getIAttribute(IATTR_HINT_DRAWABLE) == WINDOW))
273 : {
274 1 : attributes.push_back(GLX_STEREO);
275 1 : attributes.push_back(true);
276 : }
277 : #endif
278 7 : if (getIAttribute(IATTR_HINT_DOUBLEBUFFER) == ON ||
279 6 : (getIAttribute(IATTR_HINT_DOUBLEBUFFER) == AUTO &&
280 3 : getIAttribute(IATTR_HINT_DRAWABLE) == WINDOW))
281 : {
282 1 : attributes.push_back(GLX_DOUBLEBUFFER);
283 1 : attributes.push_back(true);
284 : }
285 3 : attributes.push_back(None);
286 :
287 : // build backoff list, least important attribute last
288 6 : std::vector<int> backoffAttributes;
289 3 : if (getIAttribute(IATTR_HINT_DRAWABLE) == WINDOW)
290 : {
291 1 : if (getIAttribute(IATTR_HINT_DOUBLEBUFFER) == AUTO)
292 1 : backoffAttributes.push_back(GLX_DOUBLEBUFFER);
293 :
294 : #ifndef Darwin
295 1 : if (getIAttribute(IATTR_HINT_STEREO) == AUTO)
296 1 : backoffAttributes.push_back(GLX_STEREO);
297 : #endif
298 : }
299 :
300 3 : if (stencilSize == AUTO)
301 2 : backoffAttributes.push_back(GLX_STENCIL_SIZE);
302 :
303 : PFNGLXCHOOSEFBCONFIGSGIXPROC chooseFBConfig =
304 3 : GLXEW_VERSION_1_3 ? glXChooseFBConfig : glXChooseFBConfigSGIX;
305 :
306 3 : const int screen = DefaultScreen(_impl->xDisplay);
307 3 : int nConfigs = 0;
308 : GLXFBConfig* configs =
309 3 : chooseFBConfig(_impl->xDisplay, screen, &attributes[0], &nConfigs);
310 :
311 5 : while ((nConfigs == 0 || !configs) && !backoffAttributes.empty())
312 : {
313 : // Gradually remove backoff attributes
314 1 : const int attribute = backoffAttributes.back();
315 1 : backoffAttributes.pop_back();
316 :
317 : std::vector<int>::iterator iter =
318 1 : find(attributes.begin(), attributes.end(), attribute);
319 1 : LBASSERT(iter != attributes.end());
320 1 : attributes.erase(iter, iter + 2);
321 : configs =
322 1 : chooseFBConfig(_impl->xDisplay, screen, &attributes[0], &nConfigs);
323 : }
324 :
325 3 : return configs;
326 : }
327 :
328 3 : GLXContext Window::createGLXContext(GLXFBConfig* fbConfig)
329 : {
330 3 : if (!_impl->xDisplay)
331 : {
332 0 : sendError(ERROR_GLXWINDOW_NO_DISPLAY);
333 0 : return 0;
334 : }
335 3 : if (!fbConfig)
336 : {
337 0 : sendError(ERROR_SYSTEMWINDOW_NO_PIXELFORMAT);
338 0 : return 0;
339 : }
340 :
341 3 : GLXContext shCtx = 0;
342 3 : const SystemWindow* shareWindow = getSharedContextWindow();
343 3 : if (shareWindow)
344 : {
345 : const WindowIF* shareGLXWindow =
346 1 : dynamic_cast<const WindowIF*>(shareWindow);
347 1 : if (shareGLXWindow)
348 1 : shCtx = shareGLXWindow->getGLXContext();
349 : #ifdef EQUALIZER_USE_QT5WIDGETS
350 0 : else if (dynamic_cast<const qt::WindowIF*>(shareWindow))
351 : {
352 : // allows sharing with Qt window
353 0 : shareWindow->makeCurrent();
354 0 : shCtx = glXGetCurrentContext();
355 : }
356 : #endif
357 : }
358 :
359 3 : int type = GLX_RGBA_TYPE;
360 3 : GLXContext context = 0;
361 6 : if (glXCreateContextAttribsARB &&
362 6 : getIAttribute(IATTR_HINT_CORE_PROFILE) == ON)
363 : {
364 : int attribList[] = {GLX_CONTEXT_MAJOR_VERSION_ARB,
365 0 : getIAttribute(IATTR_HINT_OPENGL_MAJOR),
366 : GLX_CONTEXT_MINOR_VERSION_ARB,
367 0 : getIAttribute(IATTR_HINT_OPENGL_MINOR),
368 : GLX_RENDER_TYPE,
369 : type,
370 : GLX_CONTEXT_PROFILE_MASK_ARB,
371 : GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
372 0 : None};
373 :
374 0 : context = glXCreateContextAttribsARB(_impl->xDisplay, fbConfig[0],
375 0 : shCtx, True, attribList);
376 : }
377 : else
378 : {
379 3 : if (GLXEW_VERSION_1_3)
380 3 : context = glXCreateNewContext(_impl->xDisplay, fbConfig[0], type,
381 3 : shCtx, True);
382 : else
383 : context =
384 0 : glXCreateContextWithConfigSGIX(_impl->xDisplay, fbConfig[0],
385 0 : type, shCtx, True);
386 : }
387 :
388 : #ifdef Darwin
389 : // WAR http://xquartz.macosforge.org/trac/ticket/466
390 : if (!context)
391 : {
392 : XVisualInfo* visInfo =
393 : GLXEW_VERSION_1_3
394 : ? glXGetVisualFromFBConfig(_impl->xDisplay, fbConfig[0])
395 : : glXGetVisualFromFBConfigSGIX(_impl->xDisplay, fbConfig[0]);
396 : if (!visInfo)
397 : {
398 : std::vector<int> attributes;
399 : attributes.push_back(GLX_RGBA);
400 : attributes.push_back(GLX_RED_SIZE);
401 : attributes.push_back(1);
402 : attributes.push_back(GLX_ALPHA_SIZE);
403 : attributes.push_back(1);
404 : attributes.push_back(GLX_DEPTH_SIZE);
405 : attributes.push_back(1);
406 : attributes.push_back(GLX_DOUBLEBUFFER);
407 : attributes.push_back(None);
408 :
409 : const int screen = DefaultScreen(_impl->xDisplay);
410 : visInfo =
411 : glXChooseVisual(_impl->xDisplay, screen, &attributes.front());
412 : if (!visInfo)
413 : {
414 : sendError(ERROR_GLXWINDOW_NO_VISUAL);
415 : return 0;
416 : }
417 : }
418 :
419 : context = glXCreateContext(_impl->xDisplay, visInfo, shCtx, True);
420 : XFree(visInfo);
421 : }
422 : #endif
423 :
424 3 : if (!context)
425 : {
426 0 : sendError(ERROR_GLXWINDOW_CREATECONTEXT_FAILED);
427 0 : return 0;
428 : }
429 3 : return context;
430 : }
431 :
432 3 : bool Window::configInitGLXDrawable(GLXFBConfig* fbConfig)
433 : {
434 3 : switch (getIAttribute(IATTR_HINT_DRAWABLE))
435 : {
436 : case FBO:
437 : case OFF:
438 : {
439 2 : const PixelViewport pvp(0, 0, 1, 1);
440 2 : setXDrawable(_createGLXWindow(fbConfig, pvp));
441 2 : return _impl->xDrawable != 0;
442 : }
443 :
444 : default:
445 0 : LBWARN << "Unknown drawable type " << getIAttribute(IATTR_HINT_DRAWABLE)
446 0 : << ", using window" << std::endl;
447 : // no break;
448 : case UNDEFINED:
449 : case WINDOW:
450 1 : return configInitGLXWindow(fbConfig);
451 : }
452 : }
453 :
454 1 : bool Window::configInitGLXWindow(GLXFBConfig* fbConfig)
455 : {
456 1 : if (!_impl->xDisplay)
457 : {
458 0 : sendError(ERROR_GLXWINDOW_NO_DISPLAY);
459 0 : return false;
460 : }
461 :
462 1 : PixelViewport pvp = getPixelViewport();
463 1 : if (getIAttribute(IATTR_HINT_FULLSCREEN) == ON)
464 : {
465 0 : const int screen = DefaultScreen(_impl->xDisplay);
466 0 : pvp.h = DisplayHeight(_impl->xDisplay, screen);
467 0 : pvp.w = DisplayWidth(_impl->xDisplay, screen);
468 0 : pvp.x = 0;
469 0 : pvp.y = 0;
470 :
471 0 : setPixelViewport(pvp);
472 : }
473 :
474 1 : XID drawable = _createGLXWindow(fbConfig, pvp);
475 1 : if (!drawable)
476 0 : return false;
477 :
478 : // map and wait for MapNotify event
479 1 : XMapWindow(_impl->xDisplay, drawable);
480 :
481 : XEvent event;
482 1 : XIfEvent(_impl->xDisplay, &event, WaitForNotify, (XPointer)(drawable));
483 :
484 1 : XMoveResizeWindow(_impl->xDisplay, drawable, pvp.x, pvp.y, pvp.w, pvp.h);
485 1 : XFlush(_impl->xDisplay);
486 :
487 : // Grab keyboard focus in fullscreen mode
488 2 : if (getIAttribute(IATTR_HINT_FULLSCREEN) == ON ||
489 1 : getIAttribute(IATTR_HINT_DECORATION) == OFF)
490 : {
491 0 : XGrabKeyboard(_impl->xDisplay, drawable, True, GrabModeAsync,
492 0 : GrabModeAsync, CurrentTime);
493 : }
494 1 : setXDrawable(drawable);
495 :
496 1 : LBVERB << "Created X11 drawable " << drawable << std::endl;
497 1 : return true;
498 : }
499 :
500 3 : XID Window::_createGLXWindow(GLXFBConfig* fbConfig, const PixelViewport& pvp)
501 : {
502 3 : if (!_impl->xDisplay)
503 : {
504 0 : sendError(ERROR_GLXWINDOW_NO_DISPLAY);
505 0 : return 0;
506 : }
507 3 : if (!fbConfig)
508 : {
509 0 : sendError(ERROR_SYSTEMWINDOW_NO_PIXELFORMAT);
510 0 : return 0;
511 : }
512 :
513 : XVisualInfo* visInfo =
514 3 : GLXEW_VERSION_1_3
515 3 : ? glXGetVisualFromFBConfig(_impl->xDisplay, fbConfig[0])
516 3 : : glXGetVisualFromFBConfigSGIX(_impl->xDisplay, fbConfig[0]);
517 3 : if (!visInfo)
518 : {
519 0 : sendError(ERROR_GLXWINDOW_NO_VISUAL);
520 0 : return 0;
521 : }
522 :
523 3 : const int screen = DefaultScreen(_impl->xDisplay);
524 3 : XID parent = RootWindow(_impl->xDisplay, screen);
525 : XSetWindowAttributes wa;
526 3 : wa.colormap =
527 3 : XCreateColormap(_impl->xDisplay, parent, visInfo->visual, AllocNone);
528 3 : wa.background_pixmap = None;
529 3 : wa.border_pixel = 0;
530 3 : wa.event_mask = StructureNotifyMask | VisibilityChangeMask | ExposureMask |
531 : KeyPressMask | KeyReleaseMask | PointerMotionMask |
532 : ButtonPressMask | ButtonReleaseMask;
533 :
534 3 : switch (getIAttribute(IATTR_HINT_DECORATION))
535 : {
536 : case ON:
537 0 : wa.override_redirect = False;
538 0 : break;
539 :
540 : case OFF:
541 0 : wa.override_redirect = True;
542 0 : break;
543 :
544 : case AUTO:
545 : default:
546 3 : wa.override_redirect =
547 3 : getIAttribute(IATTR_HINT_FULLSCREEN) == ON ? True : False;
548 3 : break;
549 : }
550 :
551 : XID drawable =
552 3 : XCreateWindow(_impl->xDisplay, parent, pvp.x, pvp.y, pvp.w, pvp.h, 0,
553 : visInfo->depth, InputOutput, visInfo->visual,
554 : CWBackPixmap | CWBorderPixel | CWEventMask | CWColormap |
555 : CWOverrideRedirect,
556 3 : &wa);
557 3 : XFree(visInfo);
558 3 : if (!drawable)
559 : {
560 0 : sendError(ERROR_GLXWINDOW_CREATEWINDOW_FAILED);
561 0 : return 0;
562 : }
563 :
564 6 : std::stringstream windowTitle;
565 3 : const std::string& name = getName();
566 :
567 3 : if (name.empty())
568 : {
569 0 : windowTitle << "Equalizer";
570 : #ifndef NDEBUG
571 0 : windowTitle << " (" << getpid() << ")";
572 : #endif
573 : }
574 : else
575 3 : windowTitle << name;
576 :
577 3 : XStoreName(_impl->xDisplay, drawable, windowTitle.str().c_str());
578 :
579 : // Register for close window request from the window manager
580 3 : Atom deleteAtom = XInternAtom(_impl->xDisplay, "WM_DELETE_WINDOW", False);
581 3 : XSetWMProtocols(_impl->xDisplay, drawable, &deleteAtom, 1);
582 :
583 3 : return drawable;
584 : }
585 :
586 6 : void Window::setXDrawable(XID drawable)
587 : {
588 6 : LBASSERT(_impl->xDisplay);
589 :
590 6 : if (_impl->xDrawable == drawable)
591 0 : return;
592 :
593 6 : if (_impl->xDrawable)
594 3 : exitEventHandler();
595 :
596 6 : _impl->xDrawable = drawable;
597 :
598 6 : if (!drawable)
599 3 : return;
600 :
601 3 : const int32_t drawableType = getIAttribute(IATTR_HINT_DRAWABLE);
602 3 : if (drawableType != OFF)
603 2 : initEventHandler();
604 :
605 : // query pixel viewport of window
606 3 : switch (drawableType)
607 : {
608 : case WINDOW:
609 : case AUTO:
610 : case UNDEFINED:
611 : {
612 : XWindowAttributes wa;
613 1 : XGetWindowAttributes(_impl->xDisplay, drawable, &wa);
614 :
615 : // position is relative to parent: translate to absolute coords
616 : ::Window root, parent, *children;
617 : unsigned nChildren;
618 :
619 1 : XQueryTree(_impl->xDisplay, drawable, &root, &parent, &children,
620 1 : &nChildren);
621 1 : if (children != 0)
622 0 : XFree(children);
623 :
624 : int x, y;
625 : ::Window childReturn;
626 2 : XTranslateCoordinates(_impl->xDisplay, parent, root, wa.x, wa.y, &x, &y,
627 2 : &childReturn);
628 :
629 1 : setPixelViewport(PixelViewport(x, y, wa.width, wa.height));
630 1 : break;
631 : }
632 : default:
633 0 : LBERROR << "Unknown drawable type " << drawableType << std::endl;
634 0 : LBUNIMPLEMENTED;
635 : case OFF:
636 : case FBO:
637 2 : LBASSERT(getPixelViewport().hasArea());
638 : }
639 : }
640 :
641 6 : void Window::setGLXContext(GLXContext context)
642 : {
643 6 : _impl->glXContext = context;
644 6 : }
645 :
646 4 : GLXContext Window::getGLXContext() const
647 : {
648 4 : return _impl->glXContext;
649 : }
650 :
651 7 : XID Window::getXDrawable() const
652 : {
653 7 : return _impl->xDrawable;
654 : }
655 :
656 13922 : Display* Window::getXDisplay()
657 : {
658 13922 : return _impl->xDisplay;
659 : }
660 :
661 12 : const GLXEWContext* Window::glxewGetContext() const
662 : {
663 12 : return _impl->glxewContext;
664 : }
665 :
666 3 : void Window::_initSwapSync()
667 : {
668 3 : if (getIAttribute(IATTR_HINT_DRAWABLE) != WINDOW)
669 2 : return;
670 :
671 1 : const int32_t swapSync = getIAttribute(WindowSettings::IATTR_HINT_SWAPSYNC);
672 1 : if (swapSync == AUTO || swapSync == UNDEFINED) // leave it alone
673 1 : return;
674 :
675 0 : if (GLXEW_SGI_swap_control)
676 0 : glXSwapIntervalSGI((swapSync < 0) ? 1 : swapSync);
677 : else
678 0 : LBWARN << "GLX_SGI_swap_control not supported, ignoring window "
679 0 : << "swapsync hint " << IAttribute(swapSync) << std::endl;
680 : }
681 :
682 3 : void Window::configExit()
683 : {
684 3 : if (!_impl->xDisplay)
685 0 : return;
686 :
687 3 : leaveNVSwapBarrier();
688 3 : configExitFBO();
689 3 : exitGLEW();
690 :
691 3 : glXMakeCurrent(_impl->xDisplay, None, 0);
692 :
693 3 : GLXContext context = getGLXContext();
694 3 : XID drawable = getXDrawable();
695 :
696 3 : setGLXContext(0);
697 3 : setXDrawable(0);
698 :
699 : // WAR assert in glXDestroyContext/xcb_io.c:183
700 3 : XSync(_impl->xDisplay, False);
701 :
702 3 : if (context)
703 3 : glXDestroyContext(_impl->xDisplay, context);
704 :
705 3 : if (drawable)
706 3 : XDestroyWindow(_impl->xDisplay, drawable);
707 :
708 3 : LBVERB << "Destroyed GLX context and X drawable " << std::endl;
709 : }
710 :
711 0 : void Window::_resize(const PixelViewport& pvp)
712 : {
713 0 : if (_impl->xDisplay && _impl->xDrawable)
714 0 : XMoveResizeWindow(_impl->xDisplay, _impl->xDrawable, pvp.x, pvp.y,
715 0 : pvp.w, pvp.h);
716 0 : }
717 :
718 15 : void Window::makeCurrent(const bool cache) const
719 : {
720 15 : LBASSERT(_impl->xDisplay);
721 15 : if (cache && isCurrent())
722 10 : return;
723 :
724 5 : glXMakeCurrent(_impl->xDisplay, _impl->xDrawable, _impl->glXContext);
725 5 : WindowIF::makeCurrent();
726 5 : if (_impl->glXContext)
727 : {
728 5 : EQ_GL_ERROR("After glXMakeCurrent");
729 : }
730 : }
731 :
732 1 : void Window::doneCurrent() const
733 : {
734 1 : LBASSERT(_impl->xDisplay);
735 1 : if (!isCurrent())
736 0 : return;
737 :
738 1 : glXMakeCurrent(_impl->xDisplay, 0, 0);
739 1 : WindowIF::doneCurrent();
740 : }
741 :
742 3 : void Window::swapBuffers()
743 : {
744 3 : LBASSERT(_impl->xDisplay);
745 3 : glXSwapBuffers(_impl->xDisplay, _impl->xDrawable);
746 3 : }
747 :
748 0 : void Window::joinNVSwapBarrier(const uint32_t group, const uint32_t barrier)
749 : {
750 0 : if (group == 0)
751 0 : return;
752 :
753 0 : if (!GLXEW_NV_swap_group)
754 : {
755 0 : LBWARN << "NV Swap group extension not supported" << std::endl;
756 0 : return;
757 : }
758 :
759 0 : const int screen = DefaultScreen(_impl->xDisplay);
760 0 : uint32_t maxBarrier = 0;
761 0 : uint32_t maxGroup = 0;
762 :
763 0 : glXQueryMaxSwapGroupsNV(_impl->xDisplay, screen, &maxGroup, &maxBarrier);
764 :
765 0 : if (group > maxGroup)
766 : {
767 0 : LBWARN << "Failed to initialize GLX_NV_swap_group: requested group "
768 0 : << group << " greater than maxGroups (" << maxGroup << ")"
769 0 : << std::endl;
770 0 : return;
771 : }
772 :
773 0 : if (barrier > maxBarrier)
774 : {
775 0 : LBWARN << "Failed to initialize GLX_NV_swap_group: requested barrier "
776 0 : << barrier << "greater than maxBarriers (" << maxBarrier << ")"
777 0 : << std::endl;
778 0 : return;
779 : }
780 :
781 0 : if (!glXJoinSwapGroupNV(_impl->xDisplay, _impl->xDrawable, group))
782 : {
783 0 : LBWARN << "Failed to join swap group " << group << std::endl;
784 0 : return;
785 : }
786 :
787 0 : _impl->glXNVSwapGroup = group;
788 :
789 0 : if (!glXBindSwapBarrierNV(_impl->xDisplay, group, barrier))
790 : {
791 0 : LBWARN << "Failed to bind swap barrier " << barrier << std::endl;
792 0 : return;
793 : }
794 :
795 0 : LBVERB << "Joined swap group " << group << " and barrier " << barrier
796 0 : << std::endl;
797 : }
798 :
799 3 : void Window::leaveNVSwapBarrier()
800 : {
801 3 : if (_impl->glXNVSwapGroup == 0)
802 3 : return;
803 :
804 0 : glXBindSwapBarrierNV(_impl->xDisplay, _impl->glXNVSwapGroup, 0);
805 0 : glXJoinSwapGroupNV(_impl->xDisplay, _impl->xDrawable, 0);
806 :
807 0 : _impl->glXNVSwapGroup = 0;
808 : }
809 :
810 0 : bool Window::processEvent(const EventType type, const XEvent& xEvent,
811 : PointerEvent& event)
812 : {
813 0 : switch (type)
814 : {
815 : case EVENT_WINDOW_POINTER_BUTTON_PRESS:
816 0 : if (getIAttribute(IATTR_HINT_GRAB_POINTER) == ON &&
817 0 : getIAttribute(IATTR_HINT_DRAWABLE) == WINDOW &&
818 : // If no other button was pressed already, capture the mouse
819 0 : event.buttons == event.button)
820 : {
821 : const unsigned eventMask =
822 0 : ButtonPressMask | ButtonReleaseMask | ButtonMotionMask;
823 : const int result =
824 0 : XGrabPointer(getXDisplay(), getXDrawable(), False, eventMask,
825 : GrabModeAsync, GrabModeAsync, None, None,
826 0 : CurrentTime);
827 0 : if (result == GrabSuccess)
828 0 : processEvent(EVENT_WINDOW_POINTER_GRAB, xEvent, event);
829 : else
830 : {
831 0 : LBWARN << "Failed to grab mouse: XGrabPointer returned "
832 0 : << result << std::endl;
833 : }
834 : }
835 0 : break;
836 :
837 : case EVENT_WINDOW_POINTER_BUTTON_RELEASE:
838 0 : if (getIAttribute(IATTR_HINT_GRAB_POINTER) == ON &&
839 0 : getIAttribute(IATTR_HINT_DRAWABLE) == WINDOW &&
840 : // If no button is pressed anymore, release the mouse
841 0 : event.buttons == PTR_BUTTON_NONE)
842 : {
843 : // Call early for consistent ordering
844 0 : const bool result = WindowIF::processEvent(type, xEvent, event);
845 0 : processEvent(EVENT_WINDOW_POINTER_UNGRAB, xEvent, event);
846 0 : XUngrabPointer(getXDisplay(), CurrentTime);
847 0 : return result;
848 : }
849 0 : break;
850 :
851 : default:
852 0 : break;
853 : }
854 0 : return WindowIF::processEvent(type, xEvent, event);
855 : }
856 :
857 2 : void Window::initEventHandler()
858 : {
859 2 : LBASSERT(!_impl->glXEventHandler);
860 2 : _impl->glXEventHandler = new EventHandler(this);
861 :
862 2 : Display* display = getXDisplay();
863 2 : LBASSERT(display);
864 2 : if (_impl->messagePump)
865 2 : _impl->messagePump->register_(display);
866 : else
867 0 : LBDEBUG << "Using glx::EventHandler without glx::MessagePump, external "
868 0 : << "event dispatch assumed" << std::endl;
869 2 : }
870 :
871 3 : void Window::exitEventHandler()
872 : {
873 3 : if (_impl->messagePump)
874 : {
875 2 : Display* display = getXDisplay();
876 2 : LBASSERT(display);
877 2 : _impl->messagePump->deregister(display);
878 : }
879 :
880 3 : delete _impl->glXEventHandler;
881 3 : _impl->glXEventHandler = 0;
882 3 : }
883 : }
884 30 : }
|