| /* | 
 |  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "test/linux/glx_renderer.h" | 
 |  | 
 | #include <X11/Xlib.h> | 
 | #include <X11/Xutil.h> | 
 | #include <stdlib.h> | 
 |  | 
 | namespace webrtc { | 
 | namespace test { | 
 |  | 
 | GlxRenderer::GlxRenderer(size_t width, size_t height) | 
 |     : width_(width), height_(height), display_(NULL), context_(NULL) { | 
 |   RTC_DCHECK_GT(width, 0); | 
 |   RTC_DCHECK_GT(height, 0); | 
 | } | 
 |  | 
 | GlxRenderer::~GlxRenderer() { | 
 |   Destroy(); | 
 | } | 
 |  | 
 | bool GlxRenderer::Init(const char* window_title) { | 
 |   if ((display_ = XOpenDisplay(NULL)) == NULL) { | 
 |     Destroy(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   int screen = DefaultScreen(display_); | 
 |  | 
 |   XVisualInfo* vi; | 
 |   int attr_list[] = { | 
 |       GLX_DOUBLEBUFFER, GLX_RGBA, GLX_RED_SIZE,   4,  GLX_GREEN_SIZE, 4, | 
 |       GLX_BLUE_SIZE,    4,        GLX_DEPTH_SIZE, 16, None, | 
 |   }; | 
 |  | 
 |   if ((vi = glXChooseVisual(display_, screen, attr_list)) == NULL) { | 
 |     Destroy(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   context_ = glXCreateContext(display_, vi, 0, true); | 
 |   if (context_ == NULL) { | 
 |     Destroy(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   XSetWindowAttributes window_attributes; | 
 |   window_attributes.colormap = XCreateColormap( | 
 |       display_, RootWindow(display_, vi->screen), vi->visual, AllocNone); | 
 |   window_attributes.border_pixel = 0; | 
 |   window_attributes.event_mask = StructureNotifyMask | ExposureMask; | 
 |   window_ = XCreateWindow(display_, RootWindow(display_, vi->screen), 0, 0, | 
 |                           width_, height_, 0, vi->depth, InputOutput, | 
 |                           vi->visual, CWBorderPixel | CWColormap | CWEventMask, | 
 |                           &window_attributes); | 
 |   XFree(vi); | 
 |  | 
 |   XSetStandardProperties(display_, window_, window_title, window_title, None, | 
 |                          NULL, 0, NULL); | 
 |  | 
 |   Atom wm_delete = XInternAtom(display_, "WM_DELETE_WINDOW", True); | 
 |   if (wm_delete != None) { | 
 |     XSetWMProtocols(display_, window_, &wm_delete, 1); | 
 |   } | 
 |  | 
 |   XMapRaised(display_, window_); | 
 |  | 
 |   if (!glXMakeCurrent(display_, window_, context_)) { | 
 |     Destroy(); | 
 |     return false; | 
 |   } | 
 |   GlRenderer::Init(); | 
 |   if (!glXMakeCurrent(display_, None, NULL)) { | 
 |     Destroy(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   Resize(width_, height_); | 
 |   return true; | 
 | } | 
 |  | 
 | void GlxRenderer::Destroy() { | 
 |   if (context_ != NULL) { | 
 |     glXMakeCurrent(display_, window_, context_); | 
 |     GlRenderer::Destroy(); | 
 |     glXMakeCurrent(display_, None, NULL); | 
 |     glXDestroyContext(display_, context_); | 
 |     context_ = NULL; | 
 |   } | 
 |  | 
 |   if (display_ != NULL) { | 
 |     XCloseDisplay(display_); | 
 |     display_ = NULL; | 
 |   } | 
 | } | 
 |  | 
 | GlxRenderer* GlxRenderer::Create(const char* window_title, | 
 |                                  size_t width, | 
 |                                  size_t height) { | 
 |   GlxRenderer* glx_renderer = new GlxRenderer(width, height); | 
 |   if (!glx_renderer->Init(window_title)) { | 
 |     // TODO(pbos): Add GLX-failed warning here? | 
 |     delete glx_renderer; | 
 |     return NULL; | 
 |   } | 
 |   return glx_renderer; | 
 | } | 
 |  | 
 | void GlxRenderer::Resize(size_t width, size_t height) { | 
 |   width_ = width; | 
 |   height_ = height; | 
 |   if (!glXMakeCurrent(display_, window_, context_)) { | 
 |     abort(); | 
 |   } | 
 |   GlRenderer::ResizeViewport(width_, height_); | 
 |   if (!glXMakeCurrent(display_, None, NULL)) { | 
 |     abort(); | 
 |   } | 
 |  | 
 |   XSizeHints* size_hints = XAllocSizeHints(); | 
 |   if (size_hints == NULL) { | 
 |     abort(); | 
 |   } | 
 |   size_hints->flags = PAspect; | 
 |   size_hints->min_aspect.x = size_hints->max_aspect.x = width_; | 
 |   size_hints->min_aspect.y = size_hints->max_aspect.y = height_; | 
 |   XSetWMNormalHints(display_, window_, size_hints); | 
 |   XFree(size_hints); | 
 |  | 
 |   XWindowChanges wc; | 
 |   wc.width = static_cast<int>(width); | 
 |   wc.height = static_cast<int>(height); | 
 |   XConfigureWindow(display_, window_, CWWidth | CWHeight, &wc); | 
 | } | 
 |  | 
 | void GlxRenderer::OnFrame(const webrtc::VideoFrame& frame) { | 
 |   if (static_cast<size_t>(frame.width()) != width_ || | 
 |       static_cast<size_t>(frame.height()) != height_) { | 
 |     Resize(static_cast<size_t>(frame.width()), | 
 |            static_cast<size_t>(frame.height())); | 
 |   } | 
 |  | 
 |   XEvent event; | 
 |   if (!glXMakeCurrent(display_, window_, context_)) { | 
 |     abort(); | 
 |   } | 
 |   while (XPending(display_)) { | 
 |     XNextEvent(display_, &event); | 
 |     switch (event.type) { | 
 |       case ConfigureNotify: | 
 |         GlRenderer::ResizeViewport(event.xconfigure.width, | 
 |                                    event.xconfigure.height); | 
 |         break; | 
 |       default: | 
 |         break; | 
 |     } | 
 |   } | 
 |  | 
 |   GlRenderer::OnFrame(frame); | 
 |   glXSwapBuffers(display_, window_); | 
 |  | 
 |   if (!glXMakeCurrent(display_, None, NULL)) { | 
 |     abort(); | 
 |   } | 
 | } | 
 | }  // namespace test | 
 | }  // namespace webrtc |