#include "config.h"
#include "X11Helper.h"
#include "PlatformDisplayX11.h"
#include "XUniquePtr.h"
namespace WebCore {
static bool validOperation = true;
static int handleXPixmapCreationError(Display*, XErrorEvent* event)
{
if (event->error_code == BadMatch || event->error_code == BadWindow || event->error_code == BadAlloc) {
validOperation = false;
switch (event->error_code) {
case BadMatch:
LOG_ERROR("BadMatch.");
break;
case BadWindow:
LOG_ERROR("BadWindow.");
break;
case BadAlloc:
LOG_ERROR("BadAlloc.");
break;
default:
break;
}
}
return 0;
}
struct OffScreenRootWindow {
OffScreenRootWindow()
{
m_window = 0;
Display* dpy = X11Helper::nativeDisplay();
if (!dpy)
return;
XSetWindowAttributes attributes;
attributes.override_redirect = true;
m_window = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), -1, -1, 1, 1, 0, BlackPixel(dpy, 0), WhitePixel(dpy, 0));
XChangeWindowAttributes(dpy, m_window, CWOverrideRedirect, &attributes);
XMapWindow(dpy, m_window);
if (!m_window)
LOG_ERROR("Failed to create offscreen root window.");
}
~OffScreenRootWindow()
{
if (!X11Helper::nativeDisplay())
return;
if (m_window) {
XUnmapWindow(X11Helper::nativeDisplay(), m_window);
XDestroyWindow(X11Helper::nativeDisplay(), m_window);
m_window = 0;
}
}
Window rootWindow()
{
return m_window;
}
private:
Window m_window;
};
ScopedXPixmapCreationErrorHandler::ScopedXPixmapCreationErrorHandler()
{
XSync(X11Helper::nativeDisplay(), false);
m_previousErrorHandler = XSetErrorHandler(handleXPixmapCreationError);
}
ScopedXPixmapCreationErrorHandler::~ScopedXPixmapCreationErrorHandler()
{
XSetErrorHandler(m_previousErrorHandler);
}
bool ScopedXPixmapCreationErrorHandler::isValidOperation() const
{
validOperation = true;
XSync(X11Helper::nativeDisplay(), false);
return validOperation;
}
void X11Helper::resizeWindow(const IntRect& newRect, const uint32_t windowId)
{
XResizeWindow(nativeDisplay(), windowId, newRect.width(), newRect.height());
XFlush(nativeDisplay());
}
void X11Helper::createPixmap(Pixmap* handleId, const XVisualInfo& visualInfo, const IntSize& size)
{
*handleId = 0;
Display* display = nativeDisplay();
if (!display)
return;
if (!visualInfo.visual) {
LOG_ERROR("Failed to find valid XVisual.");
return;
}
Window xWindow = offscreenRootWindow();
if (!xWindow) {
LOG_ERROR("Failed to create offscreen root window.");
return;
}
Pixmap tempHandleId = XCreatePixmap(display, xWindow, size.width(), size.height(), visualInfo.depth);
if (!tempHandleId) {
LOG_ERROR("Failed to create offscreen pixmap.");
return;
}
*handleId = tempHandleId;
XSync(X11Helper::nativeDisplay(), false);
}
void X11Helper::destroyPixmap(const uint32_t pixmapId)
{
if (!pixmapId)
return;
Display* display = nativeDisplay();
if (!display)
return;
XFreePixmap(display, pixmapId);
XSync(X11Helper::nativeDisplay(), false);
}
void X11Helper::createOffScreenWindow(uint32_t* handleId, const XVisualInfo& visInfo, const IntSize& size)
{
#if USE(GRAPHICS_SURFACE)
Display* display = nativeDisplay();
if (!display)
return;
if (!visInfo.visual) {
LOG_ERROR("Failed to find valid XVisual.");
return;
}
Window xWindow = offscreenRootWindow();
if (!xWindow)
return;
Colormap cmap = XCreateColormap(display, xWindow, visInfo.visual, AllocNone);
XSetWindowAttributes attribute;
attribute.background_pixel = WhitePixel(display, 0);
attribute.border_pixel = BlackPixel(display, 0);
attribute.colormap = cmap;
#if USE(GLX)
attribute.event_mask = ResizeRedirectMask;
#endif
uint32_t tempHandleId = XCreateWindow(display, xWindow, 0, 0, size.width(), size.height(), 0, visInfo.depth, InputOutput, visInfo.visual, CWBackPixel | CWBorderPixel | CWColormap, &attribute);
if (!tempHandleId) {
LOG_ERROR("Failed to create offscreen window.");
return;
}
XSetWindowBackgroundPixmap(display, tempHandleId, 0);
#if USE(GLX)
XCompositeRedirectWindow(display, tempHandleId, CompositeRedirectManual);
#endif
XMapWindow(display, tempHandleId);
*handleId = tempHandleId;
#else
UNUSED_PARAM(handleId);
UNUSED_PARAM(visInfo);
UNUSED_PARAM(size);
#endif
}
#if USE(EGL)
void X11Helper::createOffScreenWindow(uint32_t* handleId, const EGLint id, bool supportsAlpha, const IntSize& size)
{
#if USE(GRAPHICS_SURFACE)
VisualID visualId = static_cast<VisualID>(id);
if (!visualId)
return;
XVisualInfo visualInfoTemplate;
memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
visualInfoTemplate.visualid = visualId;
int matchingCount = 0;
XUniquePtr<XVisualInfo> matchingVisuals(XGetVisualInfo(nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount));
XVisualInfo* foundVisual = 0;
if (matchingVisuals) {
for (int i = 0; i< matchingCount; i++) {
XVisualInfo* temp = &matchingVisuals[i];
int matchingdepth = supportsAlpha ? 32 : 24;
if (temp->visualid == visualId && temp->depth == matchingdepth) {
foundVisual = temp;
break;
}
}
if (foundVisual)
createOffScreenWindow(handleId, *foundVisual, size);
}
#else
UNUSED_PARAM(handleId);
UNUSED_PARAM(id);
UNUSED_PARAM(size);
#endif
}
void X11Helper::createPixmap(Pixmap* handleId, const EGLint id, bool hasAlpha, const IntSize& size)
{
*handleId = 0;
VisualID visualId = static_cast<VisualID>(id);
if (!visualId)
return;
XVisualInfo visualInfoTemplate;
memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
visualInfoTemplate.visualid = visualId;
int matchingCount = 0;
XUniquePtr<XVisualInfo> matchingVisuals(XGetVisualInfo(nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount));
XVisualInfo* foundVisual = 0;
int requiredDepth = hasAlpha ? 32 : 24;
if (matchingVisuals) {
for (int i = 0; i< matchingCount; i++) {
XVisualInfo* temp = &matchingVisuals[i];
if (temp->visualid == visualId && temp->depth == requiredDepth) {
foundVisual = temp;
break;
}
}
if (foundVisual)
createPixmap(handleId, *foundVisual, size);
}
}
#endif
void X11Helper::destroyWindow(const uint32_t windowId)
{
if (!windowId)
return;
Display* display = nativeDisplay();
if (!display)
return;
XDestroyWindow(display, windowId);
}
bool X11Helper::isXRenderExtensionSupported()
{
static bool queryDone = false;
static bool supportsXRenderExtension = false;
if (!queryDone) {
queryDone = true;
#if USE(GRAPHICS_SURFACE) && USE(GLX)
Display* display = nativeDisplay();
if (display) {
int eventBasep, errorBasep;
supportsXRenderExtension = XRenderQueryExtension(display, &eventBasep, &errorBasep);
}
#endif
}
return supportsXRenderExtension;
}
Display* X11Helper::nativeDisplay()
{
return downcast<PlatformDisplayX11>(PlatformDisplay::sharedDisplay()).native();
}
Window X11Helper::offscreenRootWindow()
{
static OffScreenRootWindow offscreenWindow;
return offscreenWindow.rootWindow();
}
}