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 "tcuLnxX11.hpp" 25 #include "gluRenderConfig.hpp" 26 #include "deMemory.h" 27 28 #include <X11/Xutil.h> 29 30 namespace tcu 31 { 32 namespace lnx 33 { 34 namespace x11 35 { 36 37 DisplayBase::DisplayBase (EventState& platform) 38 : m_eventState (platform) 39 { 40 } 41 42 DisplayBase::~DisplayBase (void) 43 { 44 } 45 46 WindowBase::WindowBase () 47 : m_visible (false) 48 { 49 } 50 51 WindowBase::~WindowBase (void) 52 { 53 } 54 55 XlibDisplay::XlibDisplay (EventState& eventState, const char* name) 56 : DisplayBase (eventState) 57 { 58 m_display = XOpenDisplay((char*)name); // Won't modify argument string. 59 if (!m_display) 60 throw ResourceError("Failed to open display", name, __FILE__, __LINE__); 61 62 m_deleteAtom = XInternAtom(m_display, "WM_DELETE_WINDOW", False); 63 } 64 65 XlibDisplay::~XlibDisplay (void) 66 { 67 XCloseDisplay(m_display); 68 } 69 70 void XlibDisplay::processEvent (XEvent& event) 71 { 72 switch (event.type) 73 { 74 case ClientMessage: 75 if ((unsigned)event.xclient.data.l[0] == m_deleteAtom) 76 m_eventState.setQuitFlag(true); 77 break; 78 // note: ConfigureNotify for window is handled in setDimensions() 79 default: 80 break; 81 } 82 } 83 84 void XlibDisplay::processEvents (void) 85 { 86 XEvent event; 87 88 while (XPending(m_display)) 89 { 90 XNextEvent(m_display, &event); 91 processEvent(event); 92 } 93 } 94 95 bool XlibDisplay::getVisualInfo (VisualID visualID, XVisualInfo& dst) 96 { 97 XVisualInfo query; 98 query.visualid = visualID; 99 int numVisuals = 0; 100 XVisualInfo* response = XGetVisualInfo(m_display, VisualIDMask, &query, &numVisuals); 101 bool succ = false; 102 103 if (response != DE_NULL) 104 { 105 if (numVisuals > 0) // should be 1, but you never know... 106 { 107 dst = response[0]; 108 succ = true; 109 } 110 XFree(response); 111 } 112 113 return succ; 114 } 115 116 ::Visual* XlibDisplay::getVisual (VisualID visualID) 117 { 118 XVisualInfo info; 119 120 if (getVisualInfo(visualID, info)) 121 return info.visual; 122 123 return DE_NULL; 124 } 125 126 XlibWindow::XlibWindow (XlibDisplay& display, int width, int height, ::Visual* visual) 127 : WindowBase () 128 , m_display (display) 129 , m_colormap (None) 130 , m_window (None) 131 { 132 XSetWindowAttributes swa; 133 ::Display* const dpy = m_display.getXDisplay(); 134 ::Window root = DefaultRootWindow(dpy); 135 unsigned long mask = CWBorderPixel | CWEventMask; 136 137 // If redirect is enabled, window size can't be guaranteed and it is up to 138 // the window manager to decide whether to honor sizing requests. However, 139 // overriding that causes window to appear as an overlay, which causes 140 // other issues, so this is disabled by default. 141 const bool overrideRedirect = false; 142 143 if (overrideRedirect) 144 { 145 mask |= CWOverrideRedirect; 146 swa.override_redirect = true; 147 } 148 149 if (visual == DE_NULL) 150 visual = CopyFromParent; 151 else 152 { 153 XVisualInfo info = XVisualInfo(); 154 bool succ = display.getVisualInfo(XVisualIDFromVisual(visual), info); 155 156 TCU_CHECK_INTERNAL(succ); 157 158 root = RootWindow(dpy, info.screen); 159 m_colormap = XCreateColormap(dpy, root, visual, AllocNone); 160 swa.colormap = m_colormap; 161 mask |= CWColormap; 162 } 163 164 swa.border_pixel = 0; 165 swa.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask; 166 167 if (width == glu::RenderConfig::DONT_CARE) 168 width = DEFAULT_WINDOW_WIDTH; 169 if (height == glu::RenderConfig::DONT_CARE) 170 height = DEFAULT_WINDOW_HEIGHT; 171 172 m_window = XCreateWindow(dpy, root, 0, 0, width, height, 0, 173 CopyFromParent, InputOutput, visual, mask, &swa); 174 TCU_CHECK(m_window); 175 176 Atom deleteAtom = m_display.getDeleteAtom(); 177 XSetWMProtocols(dpy, m_window, &deleteAtom, 1); 178 XSync(dpy,false); 179 } 180 181 void XlibWindow::setVisibility (bool visible) 182 { 183 ::Display* dpy = m_display.getXDisplay(); 184 int eventType = None; 185 XEvent event; 186 187 if (visible == m_visible) 188 return; 189 190 if (visible) 191 { 192 XMapWindow(dpy, m_window); 193 eventType = MapNotify; 194 } 195 else 196 { 197 XUnmapWindow(dpy, m_window); 198 eventType = UnmapNotify; 199 } 200 201 // We are only interested about exposure/structure notify events, not user input 202 XSelectInput(dpy, m_window, ExposureMask | StructureNotifyMask); 203 204 do 205 { 206 XWindowEvent(dpy, m_window, ExposureMask | StructureNotifyMask, &event); 207 } while (event.type != eventType); 208 209 m_visible = visible; 210 } 211 212 void XlibWindow::getDimensions (int* width, int* height) const 213 { 214 int x, y; 215 ::Window root; 216 unsigned width_, height_, borderWidth, depth; 217 218 XGetGeometry(m_display.getXDisplay(), m_window, &root, &x, &y, &width_, &height_, &borderWidth, &depth); 219 if (width != DE_NULL) 220 *width = static_cast<int>(width_); 221 if (height != DE_NULL) 222 *height = static_cast<int>(height_); 223 } 224 225 void XlibWindow::setDimensions (int width, int height) 226 { 227 const unsigned int mask = CWWidth | CWHeight; 228 XWindowChanges changes; 229 ::Display* dpy = m_display.getXDisplay(); 230 XEvent myevent; 231 changes.width = width; 232 changes.height = height; 233 XConfigureWindow(dpy, m_window, mask, &changes); 234 XFlush(dpy); 235 236 for(;;) 237 { 238 XNextEvent(dpy, &myevent); 239 if (myevent.type == ConfigureNotify) { 240 XConfigureEvent e = myevent.xconfigure; 241 if (e.width == width && e.height == height) 242 break; 243 } 244 else 245 m_display.processEvent(myevent); 246 } 247 } 248 249 void XlibWindow::processEvents (void) 250 { 251 // A bit of a hack, since we don't really handle all the events. 252 m_display.processEvents(); 253 } 254 255 XlibWindow::~XlibWindow (void) 256 { 257 XDestroyWindow(m_display.getXDisplay(), m_window); 258 if (m_colormap != None) 259 XFreeColormap(m_display.getXDisplay(), m_colormap); 260 } 261 262 } // x11 263 } // lnx 264 } // tcu 265