Blob Blame History Raw
/*************************************************************************
 * Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr>    *
 * Copyright (C) 2014-2018 Martin Bříza <m@rtinbriza.cz>                 *
 * Copyright (C) 2019-2020 Jan Grulich <jgrulich@redhat.com>             *
 *                                                                       *
 * This program is free software; you can redistribute it and/or modify  *
 * it under the terms of the GNU General Public License as published by  *
 * the Free Software Foundation; either version 2 of the License, or     *
 * (at your option) any later version.                                   *
 *                                                                       *
 * This program is distributed in the hope that it will be useful,       *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 * GNU General Public License for more details.                          *
 *                                                                       *
 * You should have received a copy of the GNU General Public License     *
 * along with this program; if not, write to the                         *
 * Free Software Foundation, Inc.,                                       *
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
 *************************************************************************/

#include "adwaita.h"
#include "adwaitacolors.h"
#include "adwaitahelper.h"

#include <QApplication>
#include <QPainter>
#include <QLibrary>

#if ADWAITA_HAVE_X11
#include <X11/Xlib-xcb.h>
#endif

#ifndef M_PI
    #define M_PI 3.14159265358979323846
#endif

namespace Adwaita
{

//* contrast for arrow and treeline rendering
static const qreal arrowShade = 0.15;

//____________________________________________________________________
Helper::Helper()
{
    init();
}

// static
bool Helper::isWindowActive(const QWidget *widget)
{
    const QWindow *win = widget ? widget->window()->windowHandle() : nullptr;
    if (win) {
        return win->isActive();
    }
    return false;
}

//______________________________________________________________________________
void Helper::renderDebugFrame(QPainter *painter, const QRect &rect) const
{
    painter->save();
    painter->setRenderHints(QPainter::Antialiasing);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(Qt::red);
    painter->drawRect(QRectF(rect).adjusted(0.5, 0.5, -0.5, -0.5));
    painter->restore();
}

//______________________________________________________________________________
void Helper::renderFocusRect(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Sides sides) const
{
    if (!color.isValid())
        return;

    painter->save();
    painter->setRenderHints(QPainter::Antialiasing);
    painter->setBrush(color);

    if (!(outline.isValid() && sides)) {
        painter->setPen(Qt::NoPen);
        painter->drawRect(rect);
    } else {
        painter->setClipRect(rect);

        QRectF copy(rect);
        copy.adjust(0.5, 0.5, -0.5, -0.5);

        qreal radius(frameRadius(-1.0));
        if (!(sides & SideTop))
            copy.adjust(0, -radius, 0, 0);
        if (!(sides & SideBottom))
            copy.adjust(0, 0, 0, radius);
        if (!(sides & SideLeft))
            copy.adjust(-radius, 0, 0, 0);
        if (!(sides & SideRight))
            copy.adjust(0, 0, radius, 0);

        painter->setPen(outline);
        // painter->setBrush( Qt::NoBrush );
        painter->drawRoundedRect(copy, radius, radius);
    }

    painter->restore();
    return;
}

//______________________________________________________________________________
void Helper::renderFocusLine(QPainter *painter, const QRect &rect, const QColor &color) const
{
    if (!color.isValid())
        return;

    painter->save();

    QPen pen(color, 1);
    pen.setStyle(Qt::DotLine);

    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setPen(pen);
    painter->setBrush(Qt::NoBrush);

    painter->drawRoundedRect(rect, 1, 1);

    painter->restore();
}

//______________________________________________________________________________
void Helper::renderFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool hasFocus) const
{
    painter->setRenderHint(QPainter::Antialiasing);

    QRectF frameRect(rect.adjusted(1, 1, -1, -1));
    qreal radius(frameRadius());

    // set pen
    if (outline.isValid()) {
        if (hasFocus) {
            painter->setPen(QPen(outline, 2));
            frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        } else {
            painter->setPen(outline);
        }
        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        radius = qMax(radius - 1, qreal(0.0));

    } else {
        painter->setPen(Qt::NoPen);
    }

    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);

    // render
    painter->drawRoundedRect(frameRect, radius, radius);
}

//______________________________________________________________________________
void Helper::renderSquareFrame(QPainter *painter, const QRect &rect, QColor color, bool hasFocus) const
{
    painter->setPen(color);
    painter->drawRect(rect.adjusted(1, 1, -2, -2));
    if (hasFocus) {
        color.setAlphaF(0.5);
        painter->setPen(color);
        painter->drawRect(rect.adjusted(0, 0, -1, -1));
    }
}

//______________________________________________________________________________
void Helper::renderFlatFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool hasFocus) const
{
    painter->setRenderHint(QPainter::Antialiasing);

    QRectF frameRect(rect.adjusted(1, 1, -1, -1));
    qreal radius(frameRadius());

    // set pen
    if (outline.isValid()) {
        if (hasFocus) {
            painter->setPen(QPen(outline, 2));
            frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        } else {
            painter->setPen(outline);
        }
        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        radius = qMax(radius - 1, qreal(0.0));
    } else {
        painter->setPen(Qt::NoPen);
    }

    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);

    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    path.addRect(frameRect.adjusted(2 * radius, 0, 0, 0));
    path.addRoundedRect(frameRect.adjusted(0, 0, - 2 * radius, 0), radius, radius);

    painter->drawPath(path.simplified());

    // render
    //painter->drawRoundedRect( frameRect, radius, radius );
}

//______________________________________________________________________________
void Helper::renderSidePanelFrame(QPainter *painter, const QRect &rect, const QColor &outline, Side side) const
{
    // check color
    if (!outline.isValid())
        return;

    // adjust rect
    QRectF frameRect(rect.adjusted(1, 1, -1, -1));
    frameRect.adjust(0.5, 0.5, -0.5, -0.5);

    // setup painter
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(outline);

    // render
    switch (side) {
    case SideLeft:
        frameRect.adjust(0, 1, 0, -1);
        painter->drawLine(frameRect.topRight(), frameRect.bottomRight());
        break;
    case SideTop:
        frameRect.adjust(1, 0, -1, 0);
        painter->drawLine(frameRect.topLeft(), frameRect.topRight());
        break;
    case SideRight:
        frameRect.adjust(0, 1, 0, -1);
        painter->drawLine(frameRect.topLeft(), frameRect.bottomLeft());
        break;
    case SideBottom:
        frameRect.adjust(1, 0, -1, 0);
        painter->drawLine(frameRect.bottomLeft(), frameRect.bottomRight());
        break;
    case AllSides: {
        qreal radius(frameRadius(-1.0));
        painter->drawRoundedRect(frameRect, radius, radius);
        break;
    }
    default:
        break;
    }
}

//______________________________________________________________________________
void Helper::renderMenuFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool roundCorners) const
{
    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);

    painter->setRenderHint(QPainter::Antialiasing, false);
    QRectF frameRect(rect);
    if (outline.isValid()) {
        painter->setPen(outline);
        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
    } else
        painter->setPen(Qt::NoPen);

    painter->drawRect(frameRect);
}

//______________________________________________________________________________
void Helper::renderButtonFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow,
                               bool hasFocus, bool sunken, bool mouseOver, bool active, bool darkMode) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(1, 1, -1, -1);
    qreal radius(frameRadius());

    if (outline.isValid()) {
        painter->setPen(QPen(outline, 1.0));

        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        radius = qMax(radius - 1, qreal(0.0));
    } else
        painter->setPen(Qt::NoPen);

    // content
    if (color.isValid() && active) {
        QLinearGradient gradient(frameRect.bottomLeft(), frameRect.topLeft());
        if (sunken) {
            // Pressed button in normal and dark mode is not a gradient, just an image consting from same $color
            gradient.setColorAt(0, color);
            gradient.setColorAt(1, color);
        } else if (mouseOver) {
            if (darkMode) {
                QColor baseColor = Colors::lighten(color, 0.01);
                // Hovered button in dark mode is a gradient from $color to Colors::lighten(bg_color, 0.01)
                gradient.setColorAt(0, Colors::lighten(baseColor, 0.01)); // FIXME not correct according to adwaita's _drawing.scss file, but looks more close than before
                gradient.setColorAt(1, Colors::lighten(baseColor, 0.01));
            } else {
                QColor baseColor = color;
                // Hovered button in normal mode is a gradient from $color to Colors::lighten(bg_color, 0.01)
                gradient.setColorAt(0, color);
                gradient.setColorAt(1, Colors::lighten(baseColor, 0.01));
            }
        } else {
            if (darkMode) {
                QColor baseColor = Colors::lighten(color, 0.01);
                // Normal button in dark mode is a gradient from $color to bg_color
                gradient.setColorAt(0, color);
                gradient.setColorAt(1, baseColor);
            } else {
                QColor baseColor = Colors::lighten(color, 0.04);
                // Normal button in normal mode is a gradient from $color to bg_color
                gradient.setColorAt(0, color);
                gradient.setColorAt(1, baseColor);
            }
        }
        painter->setBrush(gradient);
    } else if (!active) {
        painter->setBrush(color);
    } else {
        painter->setBrush(Qt::NoBrush);
    }

    // render
    painter->drawRoundedRect(frameRect, radius, radius);

    if (!sunken && active && color.isValid()) {
        painter->setPen(color.lighter(140));
        painter->drawLine(frameRect.topLeft() + QPoint(3, 1), frameRect.topRight() + QPoint(-3, 1));
        painter->setPen(outline.darker(114));
        painter->drawLine(frameRect.bottomLeft() + QPointF(2.7, 0), frameRect.bottomRight() + QPointF(-2.7, 0));
    }
}

//______________________________________________________________________________
void Helper::renderCheckBoxFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow,
                                 bool hasFocus, bool sunken, bool mouseOver, bool active, CheckBoxState state, bool darkMode, bool inMenu) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(1, 1, -1, -1);
    qreal radius(frameRadius());

    if (outline.isValid()) {
        painter->setPen(QPen(outline, 1.0));

        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        radius = qMax(radius - 1, qreal(0.0));
    } else
        painter->setPen(Qt::NoPen);

    if (inMenu || state == CheckOff) {
        // content
        if (color.isValid() && active) {
            QLinearGradient gradient(frameRect.bottomLeft(), frameRect.topLeft());
            if (sunken) {
                // Pressed-alt button in dark mode is not a gradient, just an image consting from same $color
                if (darkMode) {
                    gradient.setColorAt(0, color);
                    gradient.setColorAt(1, color);
                } else {
                    // Pressed-alt button in normal mode is not a gradient, just an image consting from same $color
                    gradient.setColorAt(0, color);
                    gradient.setColorAt(1, color);
                }
            } else if (mouseOver) {
                if (darkMode) {
                    QColor baseColor = color;
                    // Hovered-alt button in dark mode is a gradient from $color to Colors::darken(bg_color, 0.04)
                    gradient.setColorAt(0, Colors::darken(baseColor, 0.04));
                    gradient.setColorAt(1, color);
                } else {
                    QColor baseColor = Colors::darken(color, 0.09);
                    // Hovered-alt button in normal mode is a gradient from $color to Colors::lighten(bg_color, 0.04)
                    gradient.setColorAt(0, color);                      // FIXME:
                    gradient.setColorAt(1, Colors::lighten(baseColor, 0.04));   // should be vice-versa, but this way it seems to be more accurate
                }
            } else {
                if (darkMode) {
                    QColor baseColor = Colors::lighten(color, 0.03);
                    // Normal-alt button in dark mode is a gradient from $color to Colors::darken(bg_color, 0.06)
                    gradient.setColorAt(0, Colors::darken(baseColor, 0.06));
                    gradient.setColorAt(1, color);
                } else {
                    QColor baseColor = Colors::darken(color, 0.05);
                    // Normal-alt button in normal mode is a gradient from $color to bg_color
                    gradient.setColorAt(0, baseColor);
                    gradient.setColorAt(1, color);
                }
            }
            painter->setBrush(gradient);
        } else if (!active) {
            painter->setBrush(color);
        } else {
            painter->setBrush(Qt::NoBrush);
        }
    } else {
        if (color.isValid()) {
            QLinearGradient gradient(frameRect.bottomLeft(), frameRect.topLeft());
            gradient.setColorAt(0, color);
            gradient.setColorAt(1, Colors::lighten(color, 0.04));
            painter->setBrush(gradient);
        } else {
            painter->setBrush(Qt::NoBrush);
        }
    }

    // render
    painter->drawRoundedRect(frameRect, radius, radius);
}

//______________________________________________________________________________
void Helper::renderFlatButtonFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow,
                                   bool hasFocus, bool sunken, bool mouseOver, bool active) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(1, 1, -1, -1);
    qreal radius(frameRadius());

    if (outline.isValid()) {
        painter->setPen(QPen(outline, 1.0));

        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        radius = qMax(radius - 1, qreal(0.0));
    } else
        painter->setPen(Qt::NoPen);

    // content
    if (color.isValid()) {
        QLinearGradient gradient(frameRect.topLeft(), frameRect.bottomLeft());
        //gradient.setColorAt( 0, color.darker( sunken ? 110 : (hasFocus|mouseOver) ? 85 : 100 ) );
        //gradient.setColorAt( 1, color.darker( sunken ? 130 : (hasFocus|mouseOver) ? 95 : 110 ) );

        if (!active) {
            gradient.setColorAt(0, color);
        } else if (sunken) {
            gradient.setColorAt(0, color);
        } else {
            gradient.setColorAt(0, Colors::mix(color, Qt::white, 0.07));
            gradient.setColorAt(1, Colors::mix(color, Qt::black, 0.1));
        }
        painter->setBrush(gradient);
    } else
        painter->setBrush(Qt::NoBrush);

    QPainterPath path;
    path.setFillRule(Qt::WindingFill);
    path.addRoundedRect(frameRect.adjusted(2 * radius, 0, 0, 0), radius, radius);
    path.addRect(frameRect.adjusted(0, 0, -2 * radius, 0));
    painter->drawPath(path.simplified());

    if (!sunken && active) {
        painter->setPen(color.lighter(140));
        painter->drawLine(frameRect.topLeft() + QPoint(1, 1), frameRect.topRight() + QPoint(-3, 1));
        painter->setPen(outline.darker(114));
        painter->drawLine(frameRect.bottomLeft() + QPointF(0.7, 0), frameRect.bottomRight() + QPointF(-2.7, 0));
    }

    // render
    //painter->drawRoundedRect( frameRect, radius, radius );
}

//______________________________________________________________________________
void Helper::renderToolButtonFrame(QPainter *painter, const QRect &rect, const QColor &color, bool sunken) const
{
    // do nothing for invalid color
    if (!color.isValid())
        return;

    // setup painter
    painter->setRenderHints(QPainter::Antialiasing);

    QRectF baseRect(rect);

    if (sunken) {
        qreal radius(frameRadius());

        painter->setPen(Qt::NoPen);
        painter->setBrush(color);

        QRectF contentRect(baseRect.adjusted(1, 1, -1, -1));
        painter->drawRoundedRect(contentRect, radius, radius);
    } else {
        qreal radius(frameRadius(-0.5));

        painter->setPen(color);
        painter->setBrush(Qt::NoBrush);
        QRectF outlineRect(baseRect.adjusted(1.5, 1.5, -1.5, -1.5));
        painter->drawRoundedRect(outlineRect, radius, radius);
    }
}

//______________________________________________________________________________
void Helper::renderToolBoxFrame(QPainter *painter, const QRect &rect, int tabWidth, const QColor &outline) const
{
    if (!outline.isValid())
        return;

    // round radius
    qreal radius(frameRadius());
    QSizeF cornerSize(2 * radius, 2 * radius);

    // if rect - tabwidth is even, need to increase tabWidth by 1 unit
    // for anti aliasing
    if (!((rect.width() - tabWidth) % 2))
        ++tabWidth;

    // adjust rect for antialiasing
    QRectF baseRect(rect);
    baseRect.adjust(0.5, 0.5, -0.5, -0.5);

    // create path
    QPainterPath path;
    path.moveTo(0, baseRect.height() - 1);
    path.lineTo((baseRect.width() - tabWidth) / 2 - radius, baseRect.height() - 1);
    path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2 - 2 * radius, baseRect.height() - 1 - 2 * radius), cornerSize), 270, 90);
    path.lineTo((baseRect.width() - tabWidth) / 2, radius);
    path.arcTo(QRectF(QPointF((baseRect.width() - tabWidth) / 2, 0), cornerSize), 180, -90);
    path.lineTo((baseRect.width() + tabWidth) / 2 - 1 - radius, 0);
    path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2  - 1 - 2 * radius, 0), cornerSize), 90, -90);
    path.lineTo((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - radius);
    path.arcTo(QRectF(QPointF((baseRect.width() + tabWidth) / 2 - 1, baseRect.height() - 1 - 2 * radius), cornerSize), 180, 90);
    path.lineTo(baseRect.width() - 1, baseRect.height() - 1);

    // render
    painter->save();
    painter->setRenderHints(QPainter::Antialiasing);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(outline);
    painter->translate(baseRect.topLeft());
    painter->drawPath(path);
    painter->restore();

    return;
}

//______________________________________________________________________________
void Helper::renderTabWidgetFrame(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, Corners corners) const
{
    painter->setRenderHint(QPainter::Antialiasing);

    QRectF frameRect(rect.adjusted(1, 1, -1, -1));
    qreal radius(frameRadius());

    // set pen
    if (outline.isValid()) {
        painter->setPen(outline);
        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
        radius = qMax(radius - 1, qreal(0.0));
    } else
        painter->setPen(Qt::NoPen);

    // set brush
    if (color.isValid())
        painter->setBrush(color);
    else
        painter->setBrush(Qt::NoBrush);

    // render
    QPainterPath path(roundedPath(frameRect, corners, radius));
    painter->drawPath(path);
}

//______________________________________________________________________________
void Helper::renderSelection(QPainter *painter, const QRect &rect, const QColor &color) const
{
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(Qt::NoPen);
    painter->setBrush(color);
    painter->drawRect(rect);
}

//______________________________________________________________________________
void Helper::renderSeparator(QPainter *painter, const QRect &rect, const QColor &color, bool vertical) const
{
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, false);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(color);

    if (vertical) {
        painter->translate(rect.width() / 2, 0);
        painter->drawLine(rect.topLeft(), rect.bottomLeft());
    } else {
        painter->translate(0, rect.height() / 2);
        painter->drawLine(rect.topLeft(), rect.topRight());
    }

    painter->restore();

    return;
}

//______________________________________________________________________________
void Helper::renderCheckBoxBackground(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool sunken) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect and radius
    QRectF frameRect(rect);
    frameRect.adjust(3, 3, -3, -3);

    painter->setPen(outline);
    painter->setBrush(color);
    painter->drawRect(frameRect);
}

//______________________________________________________________________________
void Helper::renderCheckBox(QPainter *painter, const QRect &rect, const QColor &background, const QColor &outline, const QColor &tickColor,
                            bool sunken, CheckBoxState state, bool mouseOver, qreal animation, bool active, bool darkMode, bool inMenu) const
{
    // setup painter
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect and radius
    QRectF frameRect(rect);
    frameRect.adjust(2, 2, -2, -2);
    qreal radius(frameRadius());

    // content
    {
        renderCheckBoxFrame(painter, rect, background, outline, Qt::transparent, false, sunken, mouseOver, active, state, darkMode, inMenu);
    }

    // mark
    if (state == CheckOn) {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setBrush(Qt::NoBrush);
        QPen pen(tickColor, 3);
        pen.setJoinStyle(Qt::MiterJoin);
        painter->setPen(pen);

        QRectF markerRect(frameRect);

        QPainterPath path;
        path.moveTo(markerRect.right() - markerRect.width() / 4, markerRect.top() + markerRect.height() / 3);
        path.lineTo(markerRect.center().x(), markerRect.bottom() - markerRect.height() / 3.0);
        path.lineTo(markerRect.left() + markerRect.width() / 4, markerRect.center().y());

        painter->setClipRect(markerRect);
        painter->drawPath(path);
        painter->restore();
    } else if (state == CheckPartial) {
        QPen pen(tickColor, 4);
        pen.setCapStyle(Qt::RoundCap);
        painter->setPen(pen);

        QRectF markerRect(frameRect.adjusted(4, 4, -4, -4));

        painter->drawLine(markerRect.center() - QPoint(3, 0), markerRect.center() + QPoint(3, 0));
    } else if (state == CheckAnimated) {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        painter->setBrush(Qt::NoBrush);
        QPen pen(tickColor, 3);
        pen.setJoinStyle(Qt::MiterJoin);
        painter->setPen(pen);

        QRectF markerRect(frameRect);

        QPainterPath path;
        path.moveTo(markerRect.right() - markerRect.width() / 4, markerRect.top() + markerRect.height() / 3);
        path.lineTo(markerRect.center().x(), markerRect.bottom() - markerRect.height() / 3.0);
        path.lineTo(markerRect.left() + markerRect.width() / 4, markerRect.center().y());
        path.translate(-markerRect.right(), -markerRect.top());

        painter->setClipRect(markerRect.adjusted(1, 1, -1, -1));
        painter->translate(markerRect.right(), markerRect.top());
        painter->scale(animation, 0.5 + 0.5 * animation);
        painter->drawPath(path);
        painter->restore();
    }

    painter->restore();
}

//______________________________________________________________________________
void Helper::renderRadioButtonBackground(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, bool sunken) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(3, 3, -3, -3);
    if (sunken)
        frameRect.translate(1, 1);

    painter->setPen(outline);
    painter->setBrush(color);
    painter->drawEllipse(frameRect);
}

//______________________________________________________________________________
void Helper::renderRadioButton(QPainter *painter, const QRect &rect, const QColor &background, const QColor &outline, const QColor &tickColor,
                               bool sunken, bool enabled, RadioButtonState state, qreal animation, bool mouseOver, bool darkMode, bool inMenu) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(2, 2, -2, -2);

    if (inMenu || state == RadioOff) {
        if (background.isValid() && enabled) {
            QLinearGradient gradient(frameRect.bottomLeft(), frameRect.topLeft());
            if (sunken) {
                // Pressed-alt button in normal and dark mode is not a gradient, just an image consting from same $background
                gradient.setColorAt(0, background);
                gradient.setColorAt(1, background);
            } else if (mouseOver) {
                if (darkMode) {
                    QColor baseColor = background;
                    // Hovered-alt button in dark mode is a gradient from $background to Colors::darken(bg_background, 0.04)
                    gradient.setColorAt(0, Colors::darken(baseColor, 0.04));
                    gradient.setColorAt(1, background);
                } else {
                    QColor baseColor = Colors::darken(background, 0.09);
                    // Hovered-alt button in normal mode is a gradient from $background to Colors::lighten(bg_background, 0.04)
                    gradient.setColorAt(0, background);                 // FIXME:
                    gradient.setColorAt(1, Colors::lighten(baseColor, 0.04));   // should be vice-versa, but this way it seems to be more accurate
                }
            } else {
                if (darkMode) {
                    QColor baseColor = Colors::lighten(background, 0.03);
                    // Normal-alt button in dark mode is a gradient from $background to Colors::darken(bg_background, 0.06)
                    gradient.setColorAt(0, Colors::darken(baseColor, 0.06));
                    gradient.setColorAt(1, background);
                } else {
                    QColor baseColor = Colors::darken(background, 0.05);
                    // Normal-alt button in normal mode is a gradient from $background to bg_background
                    gradient.setColorAt(0, baseColor);
                    gradient.setColorAt(1, background);
                }
            }
            painter->setBrush(gradient);
        } else if (!enabled) {
            painter->setBrush(background);
        } else {
            painter->setBrush(Qt::NoBrush);
        }

        painter->setPen(QPen(outline, 1));

        QRectF contentRect(frameRect.adjusted(0.5, 0.5, -0.5, -0.5));
        painter->drawEllipse(contentRect);
    } else {
        if (background.isValid()) {
            QLinearGradient gradient(frameRect.bottomLeft(), frameRect.topLeft());
            gradient.setColorAt(0, background);
            gradient.setColorAt(1, Colors::lighten(background, 0.04));
            painter->setBrush(gradient);
        } else {
            painter->setBrush(Qt::NoBrush);
        }

        painter->setPen(QPen(outline, 1));

        QRectF contentRect(frameRect.adjusted(0.5, 0.5, -0.5, -0.5));
        painter->drawEllipse(contentRect);
    }

    // mark
    if (state == RadioOn) {
        painter->setBrush(tickColor);
        painter->setPen(Qt::NoPen);

        QRectF markerRect(frameRect.adjusted(5, 5, -5, -5));
        painter->drawEllipse(markerRect);
    } else if (state == RadioAnimated) {
        painter->setBrush(tickColor);
        painter->setPen(Qt::NoPen);
        QRectF markerRect(frameRect.adjusted(5, 5, -5, -5));
        qreal remaining = markerRect.width() / 2.0 * (1.0 - animation);
        markerRect.adjust(remaining, remaining, -remaining, -remaining);

        painter->drawEllipse(markerRect);
    }
}

//______________________________________________________________________________
void Helper::renderSliderGroove(QPainter *painter, const QRect &rect, const QColor &color) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    QRectF baseRect(rect);
    qreal radius(0.5 * Metrics::Slider_GrooveThickness);

    // content
    if (color.isValid()) {
        painter->setPen(Qt::NoPen);
        painter->setBrush(color);
        painter->drawRoundedRect(baseRect, radius, radius);
    }

    return;
}

//______________________________________________________________________________
void Helper::renderDialGroove(QPainter *painter, const QRect &rect, const QColor &color) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    QRectF baseRect(rect);

    // content
    if (color.isValid()) {
        qreal penWidth(Metrics::Slider_GrooveThickness);
        QRectF grooveRect(rect.adjusted(penWidth / 2, penWidth / 2, -penWidth / 2, -penWidth / 2));

        painter->setPen(QPen(color, penWidth));
        painter->setBrush(Qt::NoBrush);
        painter->drawEllipse(grooveRect);
    }

    return;
}

//______________________________________________________________________________
void Helper::renderDialContents(QPainter *painter, const QRect &rect, const QColor &color, qreal first, qreal second) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    QRectF baseRect(rect);

    // content
    if (color.isValid()) {
        // setup groove rect
        qreal penWidth(Metrics::Slider_GrooveThickness);
        QRectF grooveRect(rect.adjusted(penWidth / 2, penWidth / 2, -penWidth / 2, -penWidth / 2));

        // setup angles
        int angleStart(first * 180 * 16 / M_PI);
        int angleSpan((second - first) * 180 * 16 / M_PI);

        // setup pen
        if (angleSpan != 0) {
            QPen pen(color, penWidth);
            pen.setCapStyle(Qt::RoundCap);
            painter->setPen(pen);
            painter->setBrush(Qt::NoBrush);
            painter->drawArc(grooveRect, angleStart, angleSpan);
        }
    }

    return;
}

//______________________________________________________________________________
void Helper::renderSliderHandle(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline, const QColor &shadow,
                                bool sunken, bool enabled, Side ticks, qreal angle, bool darkMode) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    // copy rect
    QRectF frameRect(rect);
    frameRect.adjust(1, 1, -1, -1);

    // set pen
    if (outline.isValid()) {
        QPen pen(outline);
        pen.setCapStyle(Qt::FlatCap);
        pen.setJoinStyle(Qt::MiterJoin);
        painter->setPen(pen);

        frameRect.adjust(0.5, 0.5, -0.5, -0.5);
    } else
        painter->setPen(Qt::NoPen);

    // set brush
    if (color.isValid() && enabled) {
        QLinearGradient gradient(frameRect.bottomLeft(), frameRect.topLeft());
        if (sunken) {
            // Pressed-alt button in normal and dark mode is not a gradient, just an image consting from same $background
            gradient.setColorAt(0, color);
            gradient.setColorAt(1, color);
        } else {
            if (darkMode) {
                QColor baseColor = Colors::lighten(color, 0.03);
                // Normal-alt button in dark mode is a gradient from $color to Colors::darken(bg_background, 0.06)
                gradient.setColorAt(0, Colors::darken(baseColor, 0.06));
                gradient.setColorAt(1, color);
            } else {
                QColor baseColor = Colors::darken(color, 0.05);
                // Normal-alt button in normal mode is a gradient from $color to bg_background
                gradient.setColorAt(0, baseColor);
                gradient.setColorAt(1, color);
            }
        }
        painter->setBrush(gradient);
    }  else if (!enabled) {
        painter->setBrush(color);
    } else {
        painter->setBrush(Qt::NoBrush);
    }

    QRect r(rect.right() - rect.height(), rect.top(), rect.height(), rect.height());
    r.adjust(4.5, 3.5, -2.5, -3.5);

    QPainterPath circle;
    circle.addEllipse(r);
    circle.closeSubpath();

    if (ticks & SideBottom) {
        QPainterPath triangle(r.center());
        triangle.moveTo(r.left() + 1.5, r.center().y() + 5.5);
        triangle.lineTo(r.center().x() + 1, r.bottom() + 4.5);
        triangle.lineTo(r.right() - 0.5, r.center().y() + 5.5);
        triangle.closeSubpath();
        circle = circle.united(triangle);
    } else if (ticks & SideTop) {
        QPainterPath triangle(r.center());
        triangle.moveTo(r.left() + 1.5, r.center().y() - 3.5);
        triangle.lineTo(r.center().x() + 1, r.top() - 2.5);
        triangle.lineTo(r.right() - 0.5, r.center().y() - 3.5);
        triangle.closeSubpath();
        circle = circle.united(triangle);
    } else if (ticks & SideLeft) {
        QPainterPath triangle(r.center());
        triangle.moveTo(r.center().x() - 3.5, r.top() + 1.5);
        triangle.lineTo(r.left() - 2.5, r.center().y() + 1);
        triangle.lineTo(r.center().x() - 3.5, r.bottom() - 0.5);
        triangle.closeSubpath();
        circle = circle.united(triangle);
    } else if (ticks & SideRight) {
        QPainterPath triangle(r.center());
        triangle.moveTo(r.center().x() + 3.5, r.top() + 1.5);
        triangle.lineTo(r.right() + 2.5, r.center().y() + 1);
        triangle.lineTo(r.center().x() + 3.5, r.bottom() - 0.5);
        triangle.closeSubpath();
        circle = circle.united(triangle);
    }

    QTransform rotate;
    rotate.translate(frameRect.center().x(), frameRect.center().y());
    rotate.rotate(angle);
    rotate.translate(-frameRect.center().x(), -frameRect.center().y());
    painter->drawPolygon(circle.toFillPolygon(rotate));
}

//______________________________________________________________________________
void Helper::renderProgressBarGroove(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->setRenderHint(QPainter::SmoothPixmapTransform, true);

    QRectF baseRect(rect);
    qreal radius(0.5);

    // content
    if (color.isValid()) {
        painter->setPen(outline);
        painter->setBrush(color);
        painter->drawRoundedRect(baseRect.translated(0.5, 0.5), radius, radius);
    }

    return;
}


//______________________________________________________________________________
void Helper::renderProgressBarBusyContents(QPainter *painter, const QRect &rect, const QColor &color, const QColor &outline,
        bool horizontal, bool reverse, int progress) const
{
    Q_UNUSED(reverse);

    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    QRectF baseRect(rect);
    qreal radius(0.25 * Metrics::ProgressBar_Thickness);
    QRectF contentRect;
    if (horizontal) {
        contentRect = QRect(baseRect.left(), baseRect.top(), Metrics::ProgressBar_BusyIndicatorSize, baseRect.height());
        contentRect.translate(fabs(progress - 50) / 50.0 * (baseRect.width() - contentRect.width()), 0);
    } else {
        contentRect = QRect(baseRect.left(), baseRect.top(), baseRect.width(), Metrics::ProgressBar_BusyIndicatorSize);
        contentRect.translate(0, fabs(progress - 50) / 50.0 * (baseRect.height() - contentRect.height()));
    }

    painter->setBrush(color);
    painter->setPen(outline);
    painter->drawRoundedRect(contentRect.translated(0.5, 0.5), radius, radius);

    return;
}

//______________________________________________________________________________
void Helper::renderScrollBarHandle(QPainter *painter, const QRect &rect, const QColor &color) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, true);

    QRectF baseRect(rect);
    qreal metric(rect.width() < rect.height() ? rect.width() : rect.height());
    qreal radius(0.5 * metric);

    // content
    if (color.isValid()) {
        painter->setPen(Qt::NoPen);
        painter->setBrush(color);
        painter->drawRoundedRect(baseRect, radius, radius);
    }

    return;
}

//______________________________________________________________________________
void Helper::renderTabBarTab(QPainter *painter, const QRect &rect, const QColor &background, const QColor &color, const QColor &outline, Corners corners, bool renderFrame) const
{
    // setup painter
    painter->setRenderHint(QPainter::Antialiasing, false);

    QRectF frameRect(rect);
    qreal adjustment;

    // pen
    if (outline.isValid()) {
        painter->setPen(outline);
        frameRect.adjust(1.0, 1.0, -1.0, -1.0);
        adjustment = 0;

        painter->setBrush(background);

        // render
        painter->drawRect(frameRect);
    } else if (!renderFrame) {
        adjustment = 9;
    }

    painter->setPen(QPen(color, 6));

    switch (corners) {
    case CornersTop:
        painter->drawLine(frameRect.left() + adjustment, frameRect.bottom(), frameRect.right() - adjustment, frameRect.bottom());
        break;
    case CornersBottom:
        painter->drawLine(frameRect.left() + adjustment, frameRect.top(), frameRect.right() - adjustment, frameRect.top());
        break;
    case CornersLeft:
        painter->drawLine(frameRect.right(), frameRect.top() + adjustment, frameRect.right(), frameRect.bottom() - adjustment);
        break;
    case CornersRight:
        painter->drawLine(frameRect.left(), frameRect.top() + adjustment, frameRect.left(), frameRect.bottom() - adjustment);
        break;
    }
}

//______________________________________________________________________________
// TODO blurry edges
void Helper::renderArrow(QPainter *painter, const QRect &rect, const QColor &color, ArrowOrientation orientation) const
{
    // define polygon
    QPolygonF arrow;
    switch (orientation) {
    case ArrowUp:
        arrow << QPointF(-4, 2) << QPointF(0, -2) << QPointF(4, 2);
        break;
    case ArrowDown:
        arrow << QPointF(-4, -2) << QPointF(0, 2) << QPointF(4, -2);
        break;
    case ArrowLeft:
        arrow << QPointF(2, -4) << QPointF(-2, 0) << QPointF(2, 4);
        break;
    case ArrowRight:
        arrow << QPointF(-2, -4) << QPointF(2, 0) << QPointF(-2, 4);
        break;
    default:
        break;
    }

    QPen pen(color, 1.2);
    pen.setCapStyle(Qt::FlatCap);
    pen.setJoinStyle(Qt::MiterJoin);

    painter->save();
    painter->setRenderHints(QPainter::Antialiasing);
    painter->translate(QRectF(rect).center());
    painter->setBrush(color);
    painter->setPen(pen);
    painter->drawPolygon(arrow);

    painter->restore();

    return;
}

void Helper::renderSign(QPainter *painter, const QRect &rect, const QColor &color, bool orientation) const
{
    QPen pen(color, 2);
    pen.setCapStyle(Qt::FlatCap);

    QRect r = rect.adjusted(1, 2, 0, 0);

    painter->setPen(pen);
    painter->drawLine(r.center() - QPointF(5, 0), r.center() + QPointF(5, 0));
    if (orientation)
        painter->drawLine(r.center() - QPointF(0, 5), r.center() + QPointF(0, 5));
}

//______________________________________________________________________________
void Helper::renderDecorationButton(QPainter *painter, const QRect &rect, const QColor &color, ButtonType buttonType, bool inverted) const
{
    painter->save();
    painter->setViewport(rect);
    painter->setWindow(0, 0, 18, 18);
    painter->setRenderHints(QPainter::Antialiasing, false);

    // initialize pen
    QPen pen;
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::MiterJoin);

    painter->setBrush(Qt::NoBrush);

    pen.setColor(color);
    pen.setCapStyle(Qt::RoundCap);
    pen.setJoinStyle(Qt::MiterJoin);
    pen.setWidthF(2.0 * qMax(1.0, 18.0 / rect.width()));
    painter->setPen(pen);

    switch (buttonType) {
    case ButtonClose: {
        painter->setRenderHints(QPainter::Antialiasing, true);
        painter->drawLine(QPointF(5, 5), QPointF(13, 13));
        painter->drawLine(13, 5, 5, 13);
        break;
    }
    case ButtonMaximize: {
        painter->drawPolyline(QPolygonF()
                              << QPointF(4, 4)
                              << QPointF(4, 14)
                              << QPointF(14, 14)
                              << QPointF(14, 4));
        break;
    }
    case ButtonMinimize: {

        painter->drawPolyline(QPolygonF()
                              << QPointF(4, 14)
                              << QPointF(14, 14));
        break;
    }
    case ButtonRestore: {
        painter->setPen(pen);
        QPolygonF rect = QPolygonF() << QPointF(0, 0) << QPointF(8, 0) << QPointF(8, 8) << QPointF(0, 8);
        painter->drawPolygon(rect.translated(7, 3));
        painter->drawPolygon(rect.translated(3, 7));
        break;
    }
    default:
        break;
    }

    painter->restore();
    return;
}

//______________________________________________________________________________
bool Helper::isX11(void)
{
    static const bool s_isX11 = qApp->platformName() == QLatin1String("xcb");
    return s_isX11;
}

bool Helper::isWayland(void)
{
    static const bool s_isWayland = qApp->platformName().startsWith(QLatin1String("wayland"));
    return s_isWayland;
}

//______________________________________________________________________________
QRectF Helper::shadowRect(const QRectF &rect) const
{
    return rect;
}

//______________________________________________________________________________
QPainterPath Helper::roundedPath(const QRectF &rect, Corners corners, qreal radius) const
{
    QPainterPath path;

    // simple cases
    if (corners == 0) {
        path.addRect(rect);
        return path;
    }

    if (corners == AllCorners) {
        path.addRoundedRect(rect, radius, radius);
        return path;
    }

    QSizeF cornerSize(2 * radius, 2 * radius);

    // rotate counterclockwise
    // top left corner
    if (corners & CornerTopLeft) {
        path.moveTo(rect.topLeft() + QPointF(radius, 0));
        path.arcTo(QRectF(rect.topLeft(), cornerSize), 90, 90);
    } else
        path.moveTo(rect.topLeft());

    // bottom left corner
    if (corners & CornerBottomLeft) {
        path.lineTo(rect.bottomLeft() - QPointF(0, radius));
        path.arcTo(QRectF(rect.bottomLeft() - QPointF(0, 2 * radius), cornerSize), 180, 90);
    } else
        path.lineTo(rect.bottomLeft());

    // bottom right corner
    if (corners & CornerBottomRight) {
        path.lineTo(rect.bottomRight() - QPointF(radius, 0));
        path.arcTo(QRectF(rect.bottomRight() - QPointF(2 * radius, 2 * radius), cornerSize), 270, 90);
    } else
        path.lineTo(rect.bottomRight());

    // top right corner
    if (corners & CornerTopRight) {
        path.lineTo(rect.topRight() + QPointF(0, radius));
        path.arcTo(QRectF(rect.topRight() - QPointF(2 * radius, 0), cornerSize), 0, 90);
    } else
        path.lineTo(rect.topRight());
    path.closeSubpath();
    return path;
}

//________________________________________________________________________________________________________
bool Helper::compositingActive(void) const
{
#if ADWAITA_HAVE_X11
    if (isX11()) {
        // direct call to X
        xcb_get_selection_owner_cookie_t cookie(xcb_get_selection_owner(connection(), _compositingManagerAtom));
        ScopedPointer<xcb_get_selection_owner_reply_t> reply(xcb_get_selection_owner_reply(connection(), cookie, nullptr));
        return reply && reply->owner;

    }
#endif

    // use KWindowSystem
    //return KWindowSystem::compositingActive();
    return false;

}

//____________________________________________________________________
bool Helper::hasAlphaChannel(const QWidget *widget) const
{
    return compositingActive() && widget && widget->testAttribute(Qt::WA_TranslucentBackground);
}

//______________________________________________________________________________________
QPixmap Helper::highDpiPixmap(int width, int height) const
{
    qreal dpiRatio(qApp->devicePixelRatio());
    QPixmap pixmap(width * dpiRatio, height * dpiRatio);
    pixmap.setDevicePixelRatio(dpiRatio);
    return pixmap;
}

//______________________________________________________________________________________
qreal Helper::devicePixelRatio(const QPixmap &pixmap) const
{
    Q_UNUSED(pixmap);
    return 1;
}

#if ADWAITA_HAVE_X11

//____________________________________________________________________
xcb_connection_t *Helper::connection(void)
{

    return QX11Info::connection();
}

//____________________________________________________________________
xcb_atom_t Helper::createAtom(const QString &name) const
{
    if (isX11()) {
        xcb_connection_t *connection(Helper::connection());
        xcb_intern_atom_cookie_t cookie(xcb_intern_atom(connection, false, name.size(), qPrintable(name)));
        ScopedPointer<xcb_intern_atom_reply_t> reply(xcb_intern_atom_reply(connection, cookie, nullptr));
        return reply ? reply->atom : 0;
    } else
        return 0;
}

#endif

//____________________________________________________________________
void Helper::init(void)
{
#if ADWAITA_HAVE_X11
    if (isX11()) {
        // create compositing screen
        QString atomName(QStringLiteral("_NET_WM_CM_S%1").arg(QX11Info::appScreen()));
        _compositingManagerAtom = createAtom(atomName);
    }
#endif
}

//____________________________________________________________________
void Helper::setVariant(QWidget *widget, const QByteArray &variant)
{
#if ADWAITA_HAVE_X11
    if (isX11() && widget) { //  && !widget->testAttribute(Qt::WA_)) {
        static const char *_GTK_THEME_VARIANT = "_GTK_THEME_VARIANT";

        // Check if already set
        QVariant var = widget->property("_GTK_THEME_VARIANT");
        if (var.isValid() && var.toByteArray() == variant) {
            return;
        }

        // Typedef's from xcb/xcb.h - copied so that there is no
        // direct xcb dependency
        typedef quint32 XcbAtom;

        struct XcbInternAtomCookie {
            unsigned int sequence;
        };

        struct XcbInternAtomReply {
            quint8  response_type;
            quint8  pad0;
            quint16 sequence;
            quint32 length;
            XcbAtom atom;
        };

        struct XcbVoidCookie {
            unsigned int sequence;
        };

        typedef void *(*XcbConnectFn)(const char *, int *);
        typedef XcbInternAtomCookie(*XcbInternAtomFn)(void *, quint8, quint16, const char *);
        typedef XcbInternAtomReply * (*XcbInternAtomReplyFn)(void *, XcbInternAtomCookie, void *);
        typedef XcbVoidCookie(*XcbChangePropertyFn)(void *, quint8, quint32, XcbAtom, XcbAtom, quint8, quint32, const void *);
        typedef int (*XcbFlushFn)(void *);

        static QLibrary *lib = 0;
        static XcbAtom variantAtom = 0;
        static XcbAtom utf8TypeAtom = 0;
        static void *xcbConn = 0;
        static XcbChangePropertyFn XcbChangePropertyFnPtr = 0;
        static XcbFlushFn XcbFlushFnPtr = 0;

        if (!lib) {
            lib = new QLibrary("libxcb", qApp);

            if (lib->load()) {
                XcbConnectFn XcbConnectFnPtr = (XcbConnectFn)lib->resolve("xcb_connect");
                XcbInternAtomFn XcbInternAtomFnPtr = (XcbInternAtomFn)lib->resolve("xcb_intern_atom");
                XcbInternAtomReplyFn XcbInternAtomReplyFnPtr = (XcbInternAtomReplyFn)lib->resolve("xcb_intern_atom_reply");

                XcbChangePropertyFnPtr = (XcbChangePropertyFn)lib->resolve("xcb_change_property");
                XcbFlushFnPtr = (XcbFlushFn)lib->resolve("xcb_flush");
                if (XcbConnectFnPtr && XcbInternAtomFnPtr && XcbInternAtomReplyFnPtr && XcbChangePropertyFnPtr && XcbFlushFnPtr) {
                    xcbConn = (*XcbConnectFnPtr)(0, 0);
                    if (xcbConn) {
                        XcbInternAtomReply *typeReply = (*XcbInternAtomReplyFnPtr)(xcbConn, (*XcbInternAtomFnPtr)(xcbConn, 0, 11, "UTF8_STRING"), 0);

                        if (typeReply) {
                            XcbInternAtomReply *gtkVarReply = (*XcbInternAtomReplyFnPtr)(xcbConn,
                                                              (*XcbInternAtomFnPtr)(xcbConn, 0, strlen(_GTK_THEME_VARIANT),
                                                                      _GTK_THEME_VARIANT), 0);
                            if (gtkVarReply) {
                                utf8TypeAtom = typeReply->atom;
                                variantAtom = gtkVarReply->atom;
                                free(gtkVarReply);
                            }
                            free(typeReply);
                        }
                    }
                }
            }
        }

        if (0 != variantAtom) {
            (*XcbChangePropertyFnPtr)(xcbConn, 0, widget->effectiveWinId(), variantAtom, utf8TypeAtom, 8,
                                      variant.length(), (const void *)variant.constData());
            (*XcbFlushFnPtr)(xcbConn);
            widget->setProperty(_GTK_THEME_VARIANT, variant);
        }
    }
#endif
}

}