1/*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 3 * ---------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief X11 utilities. 22 *//*--------------------------------------------------------------------*/ 23 24#include "tcuX11.hpp" 25#include "gluRenderConfig.hpp" 26#include "deMemory.h" 27 28#include <X11/Xutil.h> 29 30namespace tcu 31{ 32namespace x11 33{ 34 35enum 36{ 37 DEFAULT_WINDOW_WIDTH = 400, 38 DEFAULT_WINDOW_HEIGHT = 300 39}; 40 41EventState::EventState (void) 42 : m_quit(false) 43{ 44} 45 46EventState::~EventState (void) 47{ 48} 49 50void EventState::setQuitFlag (bool quit) 51{ 52 de::ScopedLock lock(m_mutex); 53 m_quit = quit; 54} 55 56bool EventState::getQuitFlag (void) 57{ 58 de::ScopedLock lock(m_mutex); 59 return m_quit; 60} 61 62Display::Display (EventState& eventState, const char* name) 63 : m_eventState (eventState) 64 , m_display (DE_NULL) 65 , m_deleteAtom (DE_NULL) 66{ 67 m_display = XOpenDisplay((char*)name); // Won't modify argument string. 68 if (!m_display) 69 throw ResourceError("Failed to open display", name, __FILE__, __LINE__); 70 71 m_deleteAtom = XInternAtom(m_display, "WM_DELETE_WINDOW", False); 72} 73 74Display::~Display (void) 75{ 76 XCloseDisplay(m_display); 77} 78 79void Display::processEvents (void) 80{ 81 XEvent event; 82 83 while (XPending(m_display)) 84 { 85 XNextEvent(m_display, &event); 86 87 // \todo [2010-10-27 pyry] Handle ConfigureNotify? 88 if (event.type == ClientMessage && (unsigned)event.xclient.data.l[0] == m_deleteAtom) 89 m_eventState.setQuitFlag(true); 90 } 91} 92 93bool Display::getVisualInfo (VisualID visualID, XVisualInfo& dst) 94{ 95 XVisualInfo query; 96 query.visualid = visualID; 97 int numVisuals = 0; 98 XVisualInfo* response = XGetVisualInfo(m_display, VisualIDMask, &query, &numVisuals); 99 bool succ = false; 100 101 if (response != DE_NULL) 102 { 103 if (numVisuals > 0) // should be 1, but you never know... 104 { 105 dst = response[0]; 106 succ = true; 107 } 108 XFree(response); 109 } 110 111 return succ; 112} 113 114::Visual* Display::getVisual (VisualID visualID) 115{ 116 XVisualInfo info; 117 118 if (getVisualInfo(visualID, info)) 119 return info.visual; 120 121 return DE_NULL; 122} 123 124Window::Window (Display& display, int width, int height, ::Visual* visual) 125 : m_display (display) 126 , m_colormap (None) 127 , m_window (None) 128 , m_visible (false) 129{ 130 XSetWindowAttributes swa; 131 ::Display* const dpy = m_display.getXDisplay(); 132 ::Window root = DefaultRootWindow(dpy); 133 unsigned long mask = CWBorderPixel | CWEventMask; 134 135 // If redirect is enabled, window size can't be guaranteed and it is up to 136 // the window manager to decide whether to honor sizing requests. However, 137 // overriding that causes window to appear as an overlay, which causes 138 // other issues, so this is disabled by default. 139 const bool overrideRedirect = false; 140 141 if (overrideRedirect) 142 { 143 mask |= CWOverrideRedirect; 144 swa.override_redirect = true; 145 } 146 147 if (visual == DE_NULL) 148 visual = CopyFromParent; 149 else 150 { 151 XVisualInfo info = XVisualInfo(); 152 bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info); 153 154 TCU_CHECK_INTERNAL(succ); 155 156 root = RootWindow(dpy, info.screen); 157 m_colormap = XCreateColormap(dpy, root, visual, AllocNone); 158 swa.colormap = m_colormap; 159 mask |= CWColormap; 160 } 161 162 swa.border_pixel = 0; 163 swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask; 164 165 if (width == glu::RenderConfig::DONT_CARE) 166 width = DEFAULT_WINDOW_WIDTH; 167 if (height == glu::RenderConfig::DONT_CARE) 168 height = DEFAULT_WINDOW_HEIGHT; 169 170 m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0, 171 CopyFromParent, InputOutput, visual, mask, &swa); 172 TCU_CHECK(m_window); 173 174 Atom deleteAtom = m_display.getDeleteAtom(); 175 XSetWMProtocols(dpy, m_window, &deleteAtom, 1); 176} 177 178void Window::setVisibility (bool visible) 179{ 180 ::Display* dpy = m_display.getXDisplay(); 181 int eventType = None; 182 XEvent event; 183 184 if (visible == m_visible) 185 return; 186 187 if (visible) 188 { 189 XMapWindow(dpy, m_window); 190 eventType = MapNotify; 191 } 192 else 193 { 194 XUnmapWindow(dpy, m_window); 195 eventType = UnmapNotify; 196 } 197 198 // We are only interested about exposure/structure notify events, not user input 199 XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask); 200 201 do 202 { 203 XNextEvent(dpy, &event); 204 } while (event.type != eventType); 205 206 m_visible = visible; 207} 208 209void Window::getDimensions (int* width, int* height) const 210{ 211 int x, y; 212 ::Window root; 213 unsigned width_, height_, borderWidth, depth; 214 215 XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth); 216 if (width != DE_NULL) 217 *width = static_cast<int>(width_); 218 if (height != DE_NULL) 219 *height = static_cast<int>(height_); 220} 221 222void Window::setDimensions (int width, int height) 223{ 224 const unsigned int mask = CWWidth | CWHeight; 225 XWindowChanges changes; 226 changes.width = width; 227 changes.height = height; 228 229 XConfigureWindow(m_display.getXDisplay(), m_window, mask, &changes); 230} 231 232void Window::processEvents (void) 233{ 234 // A bit of a hack, since we don't really handle all the events. 235 m_display.processEvents(); 236} 237 238Window::~Window (void) 239{ 240 XDestroyWindow(m_display.getXDisplay(), m_window); 241 if (m_colormap != None) 242 XFreeColormap(m_display.getXDisplay(), m_colormap); 243} 244 245} // x11 246} // tcu 247