summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/xcb/qxcbscreen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbscreen.cpp')
-rw-r--r--src/plugins/platforms/xcb/qxcbscreen.cpp357
1 files changed, 276 insertions, 81 deletions
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index 9dc7c97eab..06f4b66edb 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qxcbscreen.h"
#include "qxcbwindow.h"
@@ -62,7 +26,7 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
{
const QByteArray cmAtomName = "_NET_WM_CM_S" + QByteArray::number(m_number);
m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
- m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom);
+ m_compositingActive = connection->selectionOwner(m_net_wm_cm_atom);
m_workArea = getWorkArea();
@@ -86,7 +50,7 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
false, screen->root,
- atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK),
+ atom(QXcbAtom::Atom_NET_SUPPORTING_WM_CHECK),
XCB_ATOM_WINDOW, 0, 1024);
if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply.get()));
@@ -112,11 +76,24 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t
xcb_depth_next(&depth_iterator);
}
+
+ auto dpiChangedCallback = [](QXcbVirtualDesktop *desktop, const QByteArray &, const QVariant &property, void *) {
+ if (!desktop->setDpiFromXSettings(property))
+ return;
+ const auto dpi = desktop->forcedDpi();
+ for (QXcbScreen *screen : desktop->connection()->screens())
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->QPlatformScreen::screen(), dpi, dpi);
+ };
+ setDpiFromXSettings(xSettings()->setting("Xft/DPI"));
+ xSettings()->registerCallbackForProperty("Xft/DPI", dpiChangedCallback, nullptr);
}
QXcbVirtualDesktop::~QXcbVirtualDesktop()
{
delete m_xSettings;
+
+ for (auto cmap : std::as_const(m_visualColormaps))
+ xcb_free_colormap(xcb_connection(), cmap);
}
QDpi QXcbVirtualDesktop::dpi() const
@@ -164,7 +141,7 @@ bool QXcbVirtualDesktop::compositingActive() const
if (connection()->hasXFixes())
return m_compositingActive;
else
- return connection()->getSelectionOwner(m_net_wm_cm_atom);
+ return connection()->selectionOwner(m_net_wm_cm_atom);
}
void QXcbVirtualDesktop::handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event)
@@ -179,7 +156,7 @@ void QXcbVirtualDesktop::subscribeToXFixesSelectionNotify()
const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
- xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->getQtSelectionOwner(), m_net_wm_cm_atom, mask);
+ xcb_xfixes_select_selection_input_checked(xcb_connection(), connection()->qtSelectionOwner(), m_net_wm_cm_atom, mask);
}
}
@@ -245,7 +222,7 @@ void QXcbVirtualDesktop::handleScreenChange(xcb_randr_screen_change_notify_event
case XCB_RANDR_ROTATION_REFLECT_Y: break;
}
- for (QPlatformScreen *platformScreen: qAsConst(m_screens)) {
+ for (QPlatformScreen *platformScreen : std::as_const(m_screens)) {
QDpi ldpi = platformScreen->logicalDpi();
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(platformScreen->screen(), ldpi.first, ldpi.second);
}
@@ -258,7 +235,7 @@ void QXcbVirtualDesktop::handleScreenChange(xcb_randr_screen_change_notify_event
_NET_WORKAREA means with multiple attached monitors. This gets worse when monitors have
different dimensions and/or screens are not virtually aligned. In Qt we want the available
geometry per monitor (QScreen), not desktop (represented by _NET_WORKAREA). WM specification
- does not have an atom for this. Thus, QScreen is limted by the lack of support from the
+ does not have an atom for this. Thus, QScreen is limited by the lack of support from the
underlying system.
One option could be that Qt does WM's job of calculating this by subtracting geometries of
@@ -272,7 +249,7 @@ QRect QXcbVirtualDesktop::getWorkArea() const
{
QRect r;
auto workArea = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), false, screen()->root,
- atom(QXcbAtom::_NET_WORKAREA),
+ atom(QXcbAtom::Atom_NET_WORKAREA),
XCB_ATOM_CARDINAL, 0, 1024);
if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
// If workArea->value_len > 4, the remaining ones seem to be for WM's virtual desktops
@@ -284,7 +261,7 @@ QRect QXcbVirtualDesktop::getWorkArea() const
uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea.get());
r = QRect(geom[0], geom[1], geom[2], geom[3]);
} else {
- r = QRect(QPoint(), size());
+ r.setWidth(-1);
}
return r;
}
@@ -294,11 +271,16 @@ void QXcbVirtualDesktop::updateWorkArea()
QRect workArea = getWorkArea();
if (m_workArea != workArea) {
m_workArea = workArea;
- for (QPlatformScreen *screen : qAsConst(m_screens))
+ for (QPlatformScreen *screen : std::as_const(m_screens))
((QXcbScreen *)screen)->updateAvailableGeometry();
}
}
+QRect QXcbVirtualDesktop::availableGeometry(const QRect &screenGeometry) const
+{
+ return m_workArea.width() >= 0 ? screenGeometry & m_workArea : screenGeometry;
+}
+
static inline QSizeF sizeInMillimeters(const QSize &size, const QDpi &dpi)
{
return QSizeF(Q_MM_PER_INCH * size.width() / dpi.first,
@@ -403,6 +385,19 @@ void QXcbVirtualDesktop::readXResources()
}
}
+bool QXcbVirtualDesktop::setDpiFromXSettings(const QVariant &property)
+{
+ bool ok;
+ int dpiTimes1k = property.toInt(&ok);
+ if (!ok)
+ return false;
+ int dpi = dpiTimes1k / 1024;
+ if (m_forcedDpi == dpi)
+ return false;
+ m_forcedDpi = dpi;
+ return true;
+}
+
QSurfaceFormat QXcbVirtualDesktop::surfaceFormatFor(const QSurfaceFormat &format) const
{
const xcb_visualid_t xcb_visualid = connection()->hasDefaultVisualId() ? connection()->defaultVisualId()
@@ -479,17 +474,34 @@ quint8 QXcbVirtualDesktop::depthOfVisual(xcb_visualid_t visualid) const
return *it;
}
+xcb_colormap_t QXcbVirtualDesktop::colormapForVisual(xcb_visualid_t visualid) const
+{
+ auto it = m_visualColormaps.constFind(visualid);
+ if (it != m_visualColormaps.constEnd())
+ return *it;
+
+ auto cmap = xcb_generate_id(xcb_connection());
+ xcb_create_colormap(xcb_connection(),
+ XCB_COLORMAP_ALLOC_NONE,
+ cmap,
+ screen()->root,
+ visualid);
+ m_visualColormaps.insert(visualid, cmap);
+ return cmap;
+}
+
QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
- xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output,
- const xcb_xinerama_screen_info_t *xineramaScreenInfo, int xineramaScreenIdx)
+ xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output)
: QXcbObject(connection)
, m_virtualDesktop(virtualDesktop)
+ , m_monitor(nullptr)
, m_output(outputId)
, m_crtc(output ? output->crtc : XCB_NONE)
, m_outputName(getOutputName(output))
, m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
+ , m_cursor(std::make_unique<QXcbCursor>(connection, this))
{
- if (connection->hasXRandr()) {
+ if (connection->isAtLeastXRandR12()) {
xcb_randr_select_input(xcb_connection(), screen()->root, true);
auto crtc = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_crtc_info, xcb_connection(),
m_crtc, output ? output->timestamp : 0);
@@ -497,27 +509,34 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
updateRefreshRate(crtc->mode);
}
- } else if (xineramaScreenInfo) {
- m_geometry = QRect(xineramaScreenInfo->x_org, xineramaScreenInfo->y_org,
- xineramaScreenInfo->width, xineramaScreenInfo->height);
- m_availableGeometry = m_geometry & m_virtualDesktop->workArea();
- m_sizeMillimeters = sizeInMillimeters(m_geometry.size(), m_virtualDesktop->dpi());
- if (xineramaScreenIdx > -1)
- m_outputName += QLatin1Char('-') + QString::number(xineramaScreenIdx);
}
if (m_geometry.isEmpty())
m_geometry = QRect(QPoint(), virtualDesktop->size());
if (m_availableGeometry.isEmpty())
- m_availableGeometry = m_geometry & m_virtualDesktop->workArea();
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
if (m_sizeMillimeters.isEmpty())
m_sizeMillimeters = virtualDesktop->physicalSize();
- m_cursor = new QXcbCursor(connection, this);
+ updateColorSpaceAndEdid();
+}
- if (connection->hasXRandr()) { // Parse EDID
+void QXcbScreen::updateColorSpaceAndEdid()
+{
+ {
+ // Read colord ICC data (from GNOME settings)
+ auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(),
+ false, screen()->root,
+ connection()->atom(QXcbAtom::Atom_ICC_PROFILE),
+ XCB_ATOM_CARDINAL, 0, 8192);
+ if (reply->format == 8 && reply->type == XCB_ATOM_CARDINAL) {
+ QByteArray data(reinterpret_cast<const char *>(xcb_get_property_value(reply.get())), reply->value_len);
+ m_colorSpace = QColorSpace::fromIccProfile(data);
+ }
+ }
+ if (connection()->isAtLeastXRandR12()) { // Parse EDID
QByteArray edid = getEdid();
if (m_edid.parse(edid)) {
qCDebug(lcQpaScreen, "EDID data for output \"%s\": identifier '%s', manufacturer '%s',"
@@ -528,6 +547,27 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
m_edid.model.toLatin1().constData(),
m_edid.serialNumber.toLatin1().constData(),
m_edid.physicalSize.width(), m_edid.physicalSize.height());
+ if (!m_colorSpace.isValid()) {
+ if (m_edid.sRgb)
+ m_colorSpace = QColorSpace::SRgb;
+ else {
+ if (!m_edid.useTables) {
+ m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
+ m_edid.greenChromaticity, m_edid.blueChromaticity,
+ QColorSpace::TransferFunction::Gamma, m_edid.gamma);
+ } else {
+ if (m_edid.tables.size() == 1) {
+ m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
+ m_edid.greenChromaticity, m_edid.blueChromaticity,
+ m_edid.tables[0]);
+ } else if (m_edid.tables.size() == 3) {
+ m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
+ m_edid.greenChromaticity, m_edid.blueChromaticity,
+ m_edid.tables[0], m_edid.tables[1], m_edid.tables[2]);
+ }
+ }
+ }
+ }
} else {
// This property is defined by the xrandr spec. Parsing failure indicates a valid error,
// but keep this as debug, for details see 4f515815efc318ddc909a0399b71b8a684962f38.
@@ -535,11 +575,144 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe
"edid data: " << edid;
}
}
+ if (!m_colorSpace.isValid())
+ m_colorSpace = QColorSpace::SRgb;
+}
+
+QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
+ xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
+ : QXcbObject(connection)
+ , m_virtualDesktop(virtualDesktop)
+ , m_monitor(monitorInfo)
+ , m_cursor(std::make_unique<QXcbCursor>(connection, this))
+{
+ setMonitor(monitorInfo, timestamp);
+}
+
+void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
+{
+ if (!connection()->isAtLeastXRandR15())
+ return;
+
+ m_outputs.clear();
+ m_crtcs.clear();
+ m_output = XCB_NONE;
+ m_crtc = XCB_NONE;
+ m_singlescreen = false;
+
+ if (!monitorInfo) {
+ m_monitor = nullptr;
+ m_mode = XCB_NONE;
+ m_outputName = defaultName();
+ // TODO: Send an event to the QScreen instance that the screen changed its name
+ return;
+ }
+
+ xcb_randr_select_input(xcb_connection(), screen()->root, true);
+
+ m_monitor = monitorInfo;
+ qCDebug(lcQpaScreen) << "xcb_randr_monitor_info_t: primary=" << m_monitor->primary << ", x=" << m_monitor->x << ", y=" << m_monitor->y
+ << ", width=" << m_monitor->width << ", height=" << m_monitor->height
+ << ", width_in_millimeters=" << m_monitor->width_in_millimeters << ", height_in_millimeters=" << m_monitor->height_in_millimeters;
+ QRect monitorGeometry = QRect(m_monitor->x, m_monitor->y,
+ m_monitor->width, m_monitor->height);
+ m_sizeMillimeters = QSize(m_monitor->width_in_millimeters, m_monitor->height_in_millimeters);
+
+ int outputCount = xcb_randr_monitor_info_outputs_length(m_monitor);
+ xcb_randr_output_t *outputs = nullptr;
+ if (outputCount) {
+ outputs = xcb_randr_monitor_info_outputs(m_monitor);
+ for (int i = 0; i < outputCount; i++) {
+ auto output = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_output_info,
+ xcb_connection(), outputs[i], timestamp);
+ // Invalid, disconnected or disabled output
+ if (!output)
+ continue;
+
+ if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
+ qCDebug(lcQpaScreen, "Output %s is not connected", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
+ xcb_randr_get_output_info_name_length(output.get()))));
+ continue;
+ }
+
+ if (output->crtc == XCB_NONE) {
+ qCDebug(lcQpaScreen, "Output %s is not enabled", qPrintable(
+ QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output.get()),
+ xcb_randr_get_output_info_name_length(output.get()))));
+ continue;
+ }
+
+ m_outputs << outputs[i];
+ if (m_output == XCB_NONE) {
+ m_output = outputs[i];
+ m_outputSizeMillimeters = QSize(output->mm_width, output->mm_height);
+ }
+ m_crtcs << output->crtc;
+ if (m_crtc == XCB_NONE)
+ m_crtc = output->crtc;
+ }
+ }
+
+ if (m_crtcs.size() == 1) {
+ auto crtc = Q_XCB_REPLY(xcb_randr_get_crtc_info,
+ xcb_connection(), m_crtcs[0], timestamp);
+ m_singlescreen = (monitorGeometry == (QRect(crtc->x, crtc->y, crtc->width, crtc->height)));
+ if (m_singlescreen) {
+ if (crtc->mode) {
+ updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
+ if (mode() != crtc->mode)
+ updateRefreshRate(crtc->mode);
+ }
+ }
+ }
+
+ if (!m_singlescreen)
+ m_geometry = monitorGeometry;
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
+ if (m_geometry.isEmpty())
+ m_geometry = QRect(QPoint(), virtualDesktop()->size());
+ if (m_availableGeometry.isEmpty())
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
+
+ if (m_sizeMillimeters.isEmpty())
+ m_sizeMillimeters = virtualDesktop()->physicalSize();
+
+ m_outputName = getName(monitorInfo);
+ m_primary = false;
+ if (connection()->primaryScreenNumber() == virtualDesktop()->number()) {
+ if (monitorInfo->primary || isPrimaryInXScreen())
+ m_primary = true;
+ }
+
+ updateColorSpaceAndEdid();
+}
+
+QString QXcbScreen::defaultName()
+{
+ QString name;
+ QByteArray displayName = connection()->displayName();
+ int dotPos = displayName.lastIndexOf('.');
+ if (dotPos != -1)
+ displayName.truncate(dotPos);
+ name = QString::fromLocal8Bit(displayName) + u'.'
+ + QString::number(m_virtualDesktop->number());
+ return name;
+}
+
+bool QXcbScreen::isPrimaryInXScreen()
+{
+ auto primary = Q_XCB_REPLY(xcb_randr_get_output_primary, connection()->xcb_connection(), root());
+ if (!primary)
+ qWarning("failed to get the primary output of the screen");
+
+ const bool isPrimary = primary ? (m_monitor ? m_outputs.contains(primary->output) : m_output == primary->output) : false;
+
+ return isPrimary;
}
QXcbScreen::~QXcbScreen()
{
- delete m_cursor;
}
QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
@@ -549,11 +722,23 @@ QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(outputInfo),
xcb_randr_get_output_info_name_length(outputInfo));
} else {
+ name = defaultName();
+ }
+ return name;
+}
+
+QString QXcbScreen::getName(xcb_randr_monitor_info_t *monitorInfo)
+{
+ QString name;
+ QByteArray ba = connection()->atomName(monitorInfo->name);
+ if (!ba.isEmpty()) {
+ name = QString::fromLatin1(ba.constData());
+ } else {
QByteArray displayName = connection()->displayName();
int dotPos = displayName.lastIndexOf('.');
if (dotPos != -1)
displayName.truncate(dotPos);
- name = QString::fromLocal8Bit(displayName) + QLatin1Char('.')
+ name = QString::fromLocal8Bit(displayName) + u'.'
+ QString::number(m_virtualDesktop->number());
}
return name;
@@ -611,7 +796,7 @@ void QXcbScreen::windowShown(QXcbWindow *window)
// Freedesktop.org Startup Notification
if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) {
sendStartupMessage(QByteArrayLiteral("remove: ID=") + connection()->startupId());
- connection()->clearStartupId();
+ connection()->setStartupId({});
}
}
@@ -632,15 +817,15 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const
xcb_client_message_event_t ev;
ev.response_type = XCB_CLIENT_MESSAGE;
ev.format = 8;
- ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO_BEGIN);
+ ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO_BEGIN);
ev.sequence = 0;
ev.window = rootWindow;
int sent = 0;
- int length = message.length() + 1; // include NUL byte
+ int length = message.size() + 1; // include NUL byte
const char *data = message.constData();
do {
if (sent == 20)
- ev.type = connection()->atom(QXcbAtom::_NET_STARTUP_INFO);
+ ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO);
const int start = sent;
const int numBytes = qMin(length - start, 20);
@@ -654,7 +839,7 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const
QRect QXcbScreen::availableGeometry() const
{
static bool enforceNetWorkarea = !qEnvironmentVariableIsEmpty("QT_RELY_ON_NET_WORKAREA_ATOM");
- bool isMultiHeadSystem = virtualSiblings().length() > 1;
+ bool isMultiHeadSystem = virtualSiblings().size() > 1;
bool useScreenGeometry = isMultiHeadSystem && !enforceNetWorkarea;
return useScreenGeometry ? m_geometry : m_availableGeometry;
}
@@ -684,17 +869,23 @@ QDpi QXcbScreen::logicalDpi() const
if (forcedDpi > 0)
return QDpi(forcedDpi, forcedDpi);
- return m_virtualDesktop->dpi();
+ // Fall back to 96 DPI in case no logical DPI is set. We don't want to
+ // return physical DPI here, since that is a different type of DPI: Logical
+ // DPI typically accounts for user preference and viewing distance, and is
+ // quantized into DPI classes (96, 144, 192, etc); pysical DPI is an exact
+ // physical measure.
+ return QDpi(96, 96);
}
QPlatformCursor *QXcbScreen::cursor() const
{
- return m_cursor;
+ return m_cursor.get();
}
void QXcbScreen::setOutput(xcb_randr_output_t outputId,
xcb_randr_get_output_info_reply_t *outputInfo)
{
+ m_monitor = nullptr;
m_output = outputId;
m_crtc = outputInfo ? outputInfo->crtc : XCB_NONE;
m_mode = XCB_NONE;
@@ -704,7 +895,7 @@ void QXcbScreen::setOutput(xcb_randr_output_t outputId,
void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
{
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return;
auto crtc = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_crtc_info, xcb_connection(),
@@ -720,19 +911,23 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
switch (rotation) {
case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal
m_orientation = Qt::LandscapeOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters;
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters;
break;
case XCB_RANDR_ROTATION_ROTATE_90: // xrandr --rotate left
m_orientation = Qt::PortraitOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters.transposed();
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters.transposed();
break;
case XCB_RANDR_ROTATION_ROTATE_180: // xrandr --rotate inverted
m_orientation = Qt::InvertedLandscapeOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters;
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters;
break;
case XCB_RANDR_ROTATION_ROTATE_270: // xrandr --rotate right
m_orientation = Qt::InvertedPortraitOrientation;
- m_sizeMillimeters = m_outputSizeMillimeters.transposed();
+ if (!m_monitor)
+ m_sizeMillimeters = m_outputSizeMillimeters.transposed();
break;
}
@@ -743,7 +938,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi());
m_geometry = geometry;
- m_availableGeometry = geometry & m_virtualDesktop->workArea();
+ m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
if (m_orientation != oldOrientation)
QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation);
@@ -751,7 +946,7 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation)
void QXcbScreen::updateAvailableGeometry()
{
- QRect availableGeometry = m_geometry & m_virtualDesktop->workArea();
+ QRect availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
if (m_availableGeometry != availableGeometry) {
m_availableGeometry = availableGeometry;
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
@@ -760,7 +955,7 @@ void QXcbScreen::updateAvailableGeometry()
void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
{
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return;
if (m_mode == mode)
@@ -896,15 +1091,15 @@ QByteArray QXcbScreen::getOutputProperty(xcb_atom_t atom) const
QByteArray QXcbScreen::getEdid() const
{
QByteArray result;
- if (!connection()->hasXRandr())
+ if (!connection()->isAtLeastXRandR12())
return result;
// Try a bunch of atoms
- result = getOutputProperty(atom(QXcbAtom::EDID));
+ result = getOutputProperty(atom(QXcbAtom::AtomEDID));
if (result.isEmpty())
- result = getOutputProperty(atom(QXcbAtom::EDID_DATA));
+ result = getOutputProperty(atom(QXcbAtom::AtomEDID_DATA));
if (result.isEmpty())
- result = getOutputProperty(atom(QXcbAtom::XFree86_DDC_EDID1_RAWDATA));
+ result = getOutputProperty(atom(QXcbAtom::AtomXFree86_DDC_EDID1_RAWDATA));
return result;
}