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 30 namespace tcu 31 { 32 namespace x11 33 { 34 35 enum 36 { 37 DEFAULT_WINDOW_WIDTH = 400, 38 DEFAULT_WINDOW_HEIGHT = 300 39 }; 40 41 EventState::EventState (void) 42 : m_quit(false) 43 { 44 } 45 46 EventState::~EventState (void) 47 { 48 } 49 50 void EventState::setQuitFlag (bool quit) 51 { 52 de::ScopedLock lock(m_mutex); 53 m_quit = quit; 54 } 55 56 bool EventState::getQuitFlag (void) 57 { 58 de::ScopedLock lock(m_mutex); 59 return m_quit; 60 } 61 62 Display::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 74 Display::~Display (void) 75 { 76 XCloseDisplay(m_display); 77 } 78 79 void 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 93 bool 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 124 Window::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* dpy = m_display.getXDisplay(); 132 ::Window root = DefaultRootWindow(dpy); 133 unsigned long mask = CWBorderPixel | CWEventMask; 134 135 if (visual == DE_NULL) 136 visual = CopyFromParent; 137 else 138 { 139 XVisualInfo info = XVisualInfo(); 140 bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info); 141 142 TCU_CHECK_INTERNAL(succ); 143 144 root = RootWindow(dpy, info.screen); 145 m_colormap = XCreateColormap(dpy, root, visual, AllocNone); 146 swa.colormap = m_colormap; 147 mask |= CWColormap; 148 } 149 150 swa.border_pixel = 0; 151 swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask; 152 153 mask |= CWOverrideRedirect; 154 swa.override_redirect = true; 155 156 if (width == glu::RenderConfig::DONT_CARE) 157 width = DEFAULT_WINDOW_WIDTH; 158 if (height == glu::RenderConfig::DONT_CARE) 159 height = DEFAULT_WINDOW_HEIGHT; 160 161 m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0, 162 CopyFromParent, InputOutput, visual, mask, &swa); 163 TCU_CHECK(m_window); 164 165 Atom deleteAtom = m_display.getDeleteAtom(); 166 XSetWMProtocols(dpy, m_window, &deleteAtom, 1); 167 168 } 169 170 void Window::setVisibility (bool visible) 171 { 172 ::Display* dpy = m_display.getXDisplay(); 173 int eventType = None; 174 XEvent event; 175 176 if (visible == m_visible) 177 return; 178 179 if (visible) 180 { 181 XMapWindow(dpy, m_window); 182 eventType = MapNotify; 183 } 184 else 185 { 186 XUnmapWindow(dpy, m_window); 187 eventType = UnmapNotify; 188 } 189 190 // We are only interested about exposure/structure notify events, not user input 191 XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask); 192 193 do 194 { 195 XNextEvent(dpy, &event); 196 } while (event.type != eventType); 197 198 m_visible = visible; 199 } 200 201 void Window::getDimensions (int* width, int* height) const 202 { 203 int x, y; 204 ::Window root; 205 unsigned width_, height_, borderWidth, depth; 206 207 XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth); 208 if (width != DE_NULL) 209 *width = static_cast<int>(width_); 210 if (height != DE_NULL) 211 *height = static_cast<int>(height_); 212 } 213 214 void Window::setDimensions (int width, int height) 215 { 216 const unsigned int mask = CWWidth | CWHeight; 217 XWindowChanges changes; 218 changes.width = width; 219 changes.height = height; 220 221 XConfigureWindow(m_display.getXDisplay(), m_window, mask, &changes); 222 } 223 224 void Window::processEvents (void) 225 { 226 // A bit of a hack, since we don't really handle all the events. 227 m_display.processEvents(); 228 } 229 230 Window::~Window (void) 231 { 232 XDestroyWindow(m_display.getXDisplay(), m_window); 233 if (m_colormap != None) 234 XFreeColormap(m_display.getXDisplay(), m_colormap); 235 } 236 237 } // x11 238 } // tcu 239