RedirectedXCompositeWindow::RedirectedXCompositeWindow(const IntSize& size, GLContextNeeded needsContext)
    : m_size(size)
    , m_window(0)
    , m_parentWindow(0)
    , m_pixmap(0)
    , m_needsContext(needsContext)
    , m_surface(0)
    , m_needsNewPixmapAfterResize(false)
    , m_damage(0)
    , m_damageNotifyCallback(0)
    , m_damageNotifyData(0)
{
    Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    Screen* screen = DefaultScreenOfDisplay(display);

    // This is based on code from Chromium: src/content/common/gpu/image_transport_surface_linux.cc
    XSetWindowAttributes windowAttributes;
    windowAttributes.override_redirect = True;
    m_parentWindow = XCreateWindow(display,
        RootWindowOfScreen(screen),
        WidthOfScreen(screen) + 1, 0, 1, 1,
        0,
        CopyFromParent,
        InputOutput,
        CopyFromParent,
        CWOverrideRedirect,
        &windowAttributes);
    XMapWindow(display, m_parentWindow);

    windowAttributes.event_mask = StructureNotifyMask;
    windowAttributes.override_redirect = False;
    m_window = XCreateWindow(display,
                             m_parentWindow,
                             0, 0, size.width(), size.height(),
                             0,
                             CopyFromParent,
                             InputOutput,
                             CopyFromParent,
                             CWEventMask,
                             &windowAttributes);
    XMapWindow(display, m_window);

    if (getWindowHashMap().isEmpty())
        gdk_window_add_filter(0, reinterpret_cast<GdkFilterFunc>(filterXDamageEvent), 0);
    getWindowHashMap().add(m_window, this);

    while (1) {
        XEvent event;
        XWindowEvent(display, m_window, StructureNotifyMask, &event);
        if (event.type == MapNotify && event.xmap.window == m_window)
            break;
    }
    XSelectInput(display, m_window, NoEventMask);
    XCompositeRedirectWindow(display, m_window, CompositeRedirectManual);
    m_damage = XDamageCreate(display, m_window, XDamageReportNonEmpty);
}
RedirectedXCompositeWindow::~RedirectedXCompositeWindow()
{
    ASSERT(m_damage);
    ASSERT(m_window);
    ASSERT(m_parentWindow);

    getWindowHashMap().remove(m_window);
    if (getWindowHashMap().isEmpty())
        gdk_window_remove_filter(0, reinterpret_cast<GdkFilterFunc>(filterXDamageEvent), 0);

    Display* display = GLContext::sharedX11Display();
    XDamageDestroy(display, m_damage);
    XDestroyWindow(display, m_window);
    XDestroyWindow(display, m_parentWindow);
    cleanupPixmapAndPixmapSurface();
}
static GdkFilterReturn filterXDamageEvent(GdkXEvent* gdkXEvent, GdkEvent* event, void*)
{
    XEvent* xEvent = static_cast<XEvent*>(gdkXEvent);
    if (xEvent->type != gDamageEventBase + XDamageNotify)
        return GDK_FILTER_CONTINUE;

    XDamageNotifyEvent* damageEvent = reinterpret_cast<XDamageNotifyEvent*>(xEvent);
    WindowHashMap& windowHashMap = getWindowHashMap();
    WindowHashMap::iterator i = windowHashMap.find(damageEvent->drawable);
    if (i == windowHashMap.end())
        return GDK_FILTER_CONTINUE;

    i->value->callDamageNotifyCallback();
    XDamageSubtract(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), damageEvent->damage, None, None);
    return GDK_FILTER_REMOVE;
}