1/* 2 * Copyright (C) 2013 Intel Corporation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "X11Helper.h" 28 29namespace WebCore { 30 31// Used for handling XError. 32static bool validOperation = true; 33static int handleXPixmapCreationError(Display*, XErrorEvent* event) 34{ 35 if (event->error_code == BadMatch || event->error_code == BadWindow || event->error_code == BadAlloc) { 36 validOperation = false; 37 38 switch (event->error_code) { 39 case BadMatch: 40 LOG_ERROR("BadMatch."); 41 break; 42 case BadWindow: 43 LOG_ERROR("BadWindow."); 44 break; 45 case BadAlloc: 46 LOG_ERROR("BadAlloc."); 47 break; 48 default: 49 break; 50 } 51 } 52 53 return 0; 54} 55 56struct DisplayConnection { 57 DisplayConnection() 58 { 59 m_display = XOpenDisplay(0); 60 61 if (!m_display) 62 LOG_ERROR("Failed to make connection with X"); 63 } 64 65 ~DisplayConnection() 66 { 67 XCloseDisplay(m_display); 68 } 69 70 Display* display() { return m_display; } 71private: 72 Display* m_display; 73}; 74 75struct OffScreenRootWindow { 76 77 OffScreenRootWindow() 78 { 79 m_window = 0; 80 Display* dpy = X11Helper::nativeDisplay(); 81 if (!dpy) 82 return; 83 84 XSetWindowAttributes attributes; 85 attributes.override_redirect = true; 86 m_window = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), -1, -1, 1, 1, 0, BlackPixel(dpy, 0), WhitePixel(dpy, 0)); 87 // From http://tronche.com/gui/x/xlib/window/attributes/ 88 XChangeWindowAttributes(dpy, m_window, CWOverrideRedirect, &attributes); 89 XMapWindow(dpy, m_window); 90 91 if (!m_window) 92 LOG_ERROR("Failed to create offscreen root window."); 93 } 94 95 ~OffScreenRootWindow() 96 { 97 if (!X11Helper::nativeDisplay()) 98 return; 99 100 if (m_window) { 101 XUnmapWindow(X11Helper::nativeDisplay(), m_window); 102 XDestroyWindow(X11Helper::nativeDisplay(), m_window); 103 m_window = 0; 104 } 105 } 106 107 Window rootWindow() 108 { 109 return m_window; 110 } 111 112private: 113 Window m_window; 114}; 115 116ScopedXPixmapCreationErrorHandler::ScopedXPixmapCreationErrorHandler() 117{ 118 // XSync must be called to ensure that current errors are handled by the original handler. 119 XSync(X11Helper::nativeDisplay(), false); 120 m_previousErrorHandler = XSetErrorHandler(handleXPixmapCreationError); 121} 122 123ScopedXPixmapCreationErrorHandler::~ScopedXPixmapCreationErrorHandler() 124{ 125 // Restore the original handler. 126 XSetErrorHandler(m_previousErrorHandler); 127} 128 129bool ScopedXPixmapCreationErrorHandler::isValidOperation() const 130{ 131 validOperation = true; 132 // XSync is needed to catch possible errors as they are generated asynchronously. 133 XSync(X11Helper::nativeDisplay(), false); 134 return validOperation; 135} 136 137void X11Helper::resizeWindow(const IntRect& newRect, const uint32_t windowId) 138{ 139 XResizeWindow(nativeDisplay(), windowId, newRect.width(), newRect.height()); 140 XFlush(nativeDisplay()); 141} 142 143void X11Helper::createPixmap(Pixmap* handleId, const XVisualInfo& visualInfo, const IntSize& size) 144{ 145 *handleId = 0; 146 Display* display = nativeDisplay(); 147 if (!display) 148 return; 149 150 if (!visualInfo.visual) { 151 LOG_ERROR("Failed to find valid XVisual."); 152 return; 153 } 154 155 Window xWindow = offscreenRootWindow(); 156 if (!xWindow) { 157 LOG_ERROR("Failed to create offscreen root window."); 158 return; 159 } 160 161 Pixmap tempHandleId = XCreatePixmap(display, xWindow, size.width(), size.height(), visualInfo.depth); 162 163 if (!tempHandleId) { 164 LOG_ERROR("Failed to create offscreen pixmap."); 165 return; 166 } 167 168 *handleId = tempHandleId; 169 XSync(X11Helper::nativeDisplay(), false); 170} 171 172void X11Helper::destroyPixmap(const uint32_t pixmapId) 173{ 174 if (!pixmapId) 175 return; 176 177 Display* display = nativeDisplay(); 178 if (!display) 179 return; 180 181 XFreePixmap(display, pixmapId); 182 XSync(X11Helper::nativeDisplay(), false); 183} 184 185void X11Helper::createOffScreenWindow(uint32_t* handleId, const XVisualInfo& visInfo, const IntSize& size) 186{ 187#if USE(GRAPHICS_SURFACE) 188 Display* display = nativeDisplay(); 189 if (!display) 190 return; 191 192 if (!visInfo.visual) { 193 LOG_ERROR("Failed to find valid XVisual."); 194 return; 195 } 196 197 Window xWindow = offscreenRootWindow(); 198 if (!xWindow) 199 return; 200 201 Colormap cmap = XCreateColormap(display, xWindow, visInfo.visual, AllocNone); 202 XSetWindowAttributes attribute; 203 attribute.background_pixel = WhitePixel(display, 0); 204 attribute.border_pixel = BlackPixel(display, 0); 205 attribute.colormap = cmap; 206#if USE(GLX) 207 attribute.event_mask = ResizeRedirectMask; 208#endif 209 uint32_t tempHandleId = XCreateWindow(display, xWindow, 0, 0, size.width(), size.height(), 0, visInfo.depth, InputOutput, visInfo.visual, CWBackPixel | CWBorderPixel | CWColormap, &attribute); 210 211 if (!tempHandleId) { 212 LOG_ERROR("Failed to create offscreen window."); 213 return; 214 } 215 216 XSetWindowBackgroundPixmap(display, tempHandleId, 0); 217#if USE(GLX) 218 XCompositeRedirectWindow(display, tempHandleId, CompositeRedirectManual); 219#endif 220 XMapWindow(display, tempHandleId); 221 *handleId = tempHandleId; 222#else 223 UNUSED_PARAM(handleId); 224 UNUSED_PARAM(visInfo); 225 UNUSED_PARAM(size); 226#endif 227} 228 229#if USE(EGL) 230void X11Helper::createOffScreenWindow(uint32_t* handleId, const EGLint id, bool supportsAlpha, const IntSize& size) 231{ 232#if USE(GRAPHICS_SURFACE) 233 VisualID visualId = static_cast<VisualID>(id); 234 235 if (!visualId) 236 return; 237 238 // EGL has suggested a visual id, so get the rest of the visual info for that id. 239 XVisualInfo visualInfoTemplate; 240 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); 241 visualInfoTemplate.visualid = visualId; 242 int matchingCount = 0; 243 OwnPtrX11<XVisualInfo> matchingVisuals(XGetVisualInfo(nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount)); 244 XVisualInfo* foundVisual = 0; 245 246 if (matchingVisuals) { 247 for (int i = 0; i< matchingCount; i++) { 248 XVisualInfo* temp = &matchingVisuals[i]; 249 int matchingdepth = supportsAlpha ? 32 : 24; 250 251 if (temp->visualid == visualId && temp->depth == matchingdepth) { 252 foundVisual = temp; 253 break; 254 } 255 } 256 257 if (foundVisual) 258 createOffScreenWindow(handleId, *foundVisual, size); 259 } 260#else 261 UNUSED_PARAM(handleId); 262 UNUSED_PARAM(id); 263 UNUSED_PARAM(size); 264#endif 265} 266 267void X11Helper::createPixmap(Pixmap* handleId, const EGLint id, bool hasAlpha, const IntSize& size) 268{ 269 *handleId = 0; 270 VisualID visualId = static_cast<VisualID>(id); 271 272 if (!visualId) 273 return; 274 275 // EGL has suggested a visual id, so get the rest of the visual info for that id. 276 XVisualInfo visualInfoTemplate; 277 memset(&visualInfoTemplate, 0, sizeof(XVisualInfo)); 278 visualInfoTemplate.visualid = visualId; 279 int matchingCount = 0; 280 OwnPtrX11<XVisualInfo> matchingVisuals(XGetVisualInfo(nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount)); 281 XVisualInfo* foundVisual = 0; 282 int requiredDepth = hasAlpha ? 32 : 24; 283 284 if (matchingVisuals) { 285 for (int i = 0; i< matchingCount; i++) { 286 XVisualInfo* temp = &matchingVisuals[i]; 287 288 if (temp->visualid == visualId && temp->depth == requiredDepth) { 289 foundVisual = temp; 290 break; 291 } 292 } 293 294 if (foundVisual) 295 createPixmap(handleId, *foundVisual, size); 296 } 297} 298#endif 299 300void X11Helper::destroyWindow(const uint32_t windowId) 301{ 302 if (!windowId) 303 return; 304 305 Display* display = nativeDisplay(); 306 if (!display) 307 return; 308 309 XDestroyWindow(display, windowId); 310} 311 312bool X11Helper::isXRenderExtensionSupported() 313{ 314 static bool queryDone = false; 315 static bool supportsXRenderExtension = false; 316 317 if (!queryDone) { 318 queryDone = true; 319#if USE(GRAPHICS_SURFACE) && USE(GLX) 320 Display* display = nativeDisplay(); 321 322 if (display) { 323 int eventBasep, errorBasep; 324 supportsXRenderExtension = XRenderQueryExtension(display, &eventBasep, &errorBasep); 325 } 326#endif 327 } 328 329 return supportsXRenderExtension; 330} 331 332Display* X11Helper::nativeDisplay() 333{ 334 // Display connection will only be broken at program shutdown. 335 static DisplayConnection displayConnection; 336 return displayConnection.display(); 337} 338 339Window X11Helper::offscreenRootWindow() 340{ 341 static OffScreenRootWindow offscreenWindow; 342 return offscreenWindow.rootWindow(); 343} 344 345} 346