blob: 6a483fc7e56c90a05a3720fef7e7e8ac8cd68ab6 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtCore/qrandom.h>
#include "qxcbconnection.h"
#include "qcolormap_x11_p.h"
#include "qxcbnativepainting.h"
#include "qt_x11_p.h"
QT_BEGIN_NAMESPACE
QXcbX11Data *qt_x11Data = nullptr;
void qt_xcb_native_x11_info_init(QXcbConnection *conn)
{
qt_x11Data = new QXcbX11Data;
X11->display = static_cast<Display *>(conn->xlib_display());
X11->defaultScreen = DefaultScreen(X11->display);
X11->screenCount = ScreenCount(X11->display);
X11->screens = new QX11InfoData[X11->screenCount];
X11->argbVisuals = new Visual *[X11->screenCount];
X11->argbColormaps = new Colormap[X11->screenCount];
for (int s = 0; s < X11->screenCount; s++) {
QX11InfoData *screen = X11->screens + s;
//screen->ref = 1; // ensures it doesn't get deleted
screen->screen = s;
int widthMM = DisplayWidthMM(X11->display, s);
if (widthMM != 0) {
screen->dpiX = (DisplayWidth(X11->display, s) * 254 + widthMM * 5) / (widthMM * 10);
} else {
screen->dpiX = 72;
}
int heightMM = DisplayHeightMM(X11->display, s);
if (heightMM != 0) {
screen->dpiY = (DisplayHeight(X11->display, s) * 254 + heightMM * 5) / (heightMM * 10);
} else {
screen->dpiY = 72;
}
X11->argbVisuals[s] = 0;
X11->argbColormaps[s] = 0;
}
X11->use_xrender = conn->hasXRender() && !qEnvironmentVariableIsSet("QT_XCB_NATIVE_PAINTING_NO_XRENDER");
#if QT_CONFIG(xrender)
memset(X11->solid_fills, 0, sizeof(X11->solid_fills));
for (int i = 0; i < X11->solid_fill_count; ++i)
X11->solid_fills[i].screen = -1;
memset(X11->pattern_fills, 0, sizeof(X11->pattern_fills));
for (int i = 0; i < X11->pattern_fill_count; ++i)
X11->pattern_fills[i].screen = -1;
#endif
QXcbColormap::initialize();
#if QT_CONFIG(xrender)
if (X11->use_xrender) {
// XRender is supported, let's see if we have a PictFormat for the
// default visual
XRenderPictFormat *format =
XRenderFindVisualFormat(X11->display,
(Visual *) QXcbX11Info::appVisual(X11->defaultScreen));
if (!format) {
X11->use_xrender = false;
}
}
#endif // QT_CONFIG(xrender)
}
QVector<XRectangle> qt_region_to_xrectangles(const QRegion &r)
{
const int numRects = r.rectCount();
const auto input = r.begin();
QVector<XRectangle> output(numRects);
for (int i = 0; i < numRects; ++i) {
const QRect &in = input[i];
XRectangle &out = output[i];
out.x = qMax(SHRT_MIN, in.x());
out.y = qMax(SHRT_MIN, in.y());
out.width = qMin((int)USHRT_MAX, in.width());
out.height = qMin((int)USHRT_MAX, in.height());
}
return output;
}
class QXcbX11InfoData : public QSharedData, public QX11InfoData
{};
QXcbX11Info::QXcbX11Info()
: d(nullptr)
{}
QXcbX11Info::~QXcbX11Info()
{}
QXcbX11Info::QXcbX11Info(const QXcbX11Info &other)
: d(other.d)
{}
QXcbX11Info &QXcbX11Info::operator=(const QXcbX11Info &other)
{
d = other.d;
return *this;
}
QXcbX11Info QXcbX11Info::fromScreen(int screen)
{
QXcbX11InfoData *xd = new QXcbX11InfoData;
xd->screen = screen;
xd->depth = QXcbX11Info::appDepth(screen);
xd->cells = QXcbX11Info::appCells(screen);
xd->colormap = QXcbX11Info::appColormap(screen);
xd->defaultColormap = QXcbX11Info::appDefaultColormap(screen);
xd->visual = (Visual *)QXcbX11Info::appVisual(screen);
xd->defaultVisual = QXcbX11Info::appDefaultVisual(screen);
QXcbX11Info info;
info.d = xd;
return info;
}
void QXcbX11Info::setDepth(int depth)
{
if (!d)
*this = fromScreen(appScreen());
d->depth = depth;
}
Display *QXcbX11Info::display()
{
return X11 ? X11->display : 0;
}
int QXcbX11Info::screen() const
{
return d ? d->screen : QXcbX11Info::appScreen();
}
int QXcbX11Info::depth() const
{
return d ? d->depth : QXcbX11Info::appDepth();
}
Colormap QXcbX11Info::colormap() const
{
return d ? d->colormap : QXcbX11Info::appColormap();
}
void *QXcbX11Info::visual() const
{
return d ? d->visual : QXcbX11Info::appVisual();
}
void QXcbX11Info::setVisual(void *visual)
{
if (!d)
*this = fromScreen(appScreen());
d->visual = (Visual *) visual;
}
int QXcbX11Info::appScreen()
{
return X11 ? X11->defaultScreen : 0;
}
int QXcbX11Info::appDepth(int screen)
{
return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].depth : 32;
}
int QXcbX11Info::appCells(int screen)
{
return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].cells : 0;
}
Colormap QXcbX11Info::appColormap(int screen)
{
return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].colormap : 0;
}
void *QXcbX11Info::appVisual(int screen)
{
return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].visual : 0;
}
Window QXcbX11Info::appRootWindow(int screen)
{
return X11 ? RootWindow(X11->display, screen == -1 ? X11->defaultScreen : screen) : 0;
}
bool QXcbX11Info::appDefaultColormap(int screen)
{
return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].defaultColormap : true;
}
bool QXcbX11Info::appDefaultVisual(int screen)
{
return X11 ? X11->screens[screen == -1 ? X11->defaultScreen : screen].defaultVisual : true;
}
int QXcbX11Info::appDpiX(int screen)
{
if (!X11)
return 75;
if (screen < 0)
screen = X11->defaultScreen;
if (screen > X11->screenCount)
return 0;
return X11->screens[screen].dpiX;
}
int QXcbX11Info::appDpiY(int screen)
{
if (!X11)
return 75;
if (screen < 0)
screen = X11->defaultScreen;
if (screen > X11->screenCount)
return 0;
return X11->screens[screen].dpiY;
}
#if QT_CONFIG(xrender)
Picture QXcbX11Data::getSolidFill(int screen, const QColor &c)
{
if (!X11->use_xrender)
return XNone;
XRenderColor color = preMultiply(c);
for (int i = 0; i < X11->solid_fill_count; ++i) {
if (X11->solid_fills[i].screen == screen
&& X11->solid_fills[i].color.alpha == color.alpha
&& X11->solid_fills[i].color.red == color.red
&& X11->solid_fills[i].color.green == color.green
&& X11->solid_fills[i].color.blue == color.blue)
return X11->solid_fills[i].picture;
}
// none found, replace one
int i = QRandomGenerator::global()->generate() % 16;
if (X11->solid_fills[i].screen != screen && X11->solid_fills[i].picture) {
XRenderFreePicture (X11->display, X11->solid_fills[i].picture);
X11->solid_fills[i].picture = 0;
}
if (!X11->solid_fills[i].picture) {
Pixmap pixmap = XCreatePixmap (X11->display, RootWindow (X11->display, screen), 1, 1, 32);
XRenderPictureAttributes attrs;
attrs.repeat = True;
X11->solid_fills[i].picture = XRenderCreatePicture (X11->display, pixmap,
XRenderFindStandardFormat(X11->display, PictStandardARGB32),
CPRepeat, &attrs);
XFreePixmap (X11->display, pixmap);
}
X11->solid_fills[i].color = color;
X11->solid_fills[i].screen = screen;
XRenderFillRectangle (X11->display, PictOpSrc, X11->solid_fills[i].picture, &color, 0, 0, 1, 1);
return X11->solid_fills[i].picture;
}
XRenderColor QXcbX11Data::preMultiply(const QColor &c)
{
XRenderColor color;
const uint A = c.alpha(),
R = c.red(),
G = c.green(),
B = c.blue();
color.alpha = (A | A << 8);
color.red = (R | R << 8) * color.alpha / 0x10000;
color.green = (G | G << 8) * color.alpha / 0x10000;
color.blue = (B | B << 8) * color.alpha / 0x10000;
return color;
}
#endif // QT_CONFIG(xrender)
QT_END_NAMESPACE