diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbscreen.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbscreen.cpp | 603 |
1 files changed, 327 insertions, 276 deletions
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index 5e136b5d7e..ec0f9ba561 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -65,6 +65,67 @@ QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t m_compositingActive = connection->getSelectionOwner(m_net_wm_cm_atom); m_workArea = getWorkArea(); + + readXResources(); + + auto rootAttribs = Q_XCB_REPLY_UNCHECKED(xcb_get_window_attributes, xcb_connection(), + screen->root); + const quint32 existingEventMask = !rootAttribs ? 0 : rootAttribs->your_event_mask; + + const quint32 mask = XCB_CW_EVENT_MASK; + const quint32 values[] = { + // XCB_CW_EVENT_MASK + XCB_EVENT_MASK_ENTER_WINDOW + | XCB_EVENT_MASK_LEAVE_WINDOW + | XCB_EVENT_MASK_PROPERTY_CHANGE + | XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification). + | existingEventMask // don't overwrite the event mask on the root window + }; + + xcb_change_window_attributes(xcb_connection(), screen->root, mask, values); + + auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), + false, screen->root, + atom(QXcbAtom::_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())); + + if (windowManager != XCB_WINDOW_NONE) { + auto windowManagerReply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), + false, windowManager, + atom(QXcbAtom::_NET_WM_NAME), + atom(QXcbAtom::UTF8_STRING), 0, 1024); + if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) { + m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply.get()), + xcb_get_property_value_length(windowManagerReply.get())); + } + } + } + + const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id); + if (!sync_reply || !sync_reply->present) + m_syncRequestSupported = false; + else + m_syncRequestSupported = true; + + xcb_depth_iterator_t depth_iterator = + xcb_screen_allowed_depths_iterator(screen); + + while (depth_iterator.rem) { + xcb_depth_t *depth = depth_iterator.data; + xcb_visualtype_iterator_t visualtype_iterator = + xcb_depth_visuals_iterator(depth); + + while (visualtype_iterator.rem) { + xcb_visualtype_t *visualtype = visualtype_iterator.data; + m_visuals.insert(visualtype->visual_id, *visualtype); + m_visualDepths.insert(visualtype->visual_id, depth->depth); + xcb_visualtype_next(&visualtype_iterator); + } + + xcb_depth_next(&depth_iterator); + } } QXcbVirtualDesktop::~QXcbVirtualDesktop() @@ -123,18 +184,33 @@ 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; - Q_XCB_CALL(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()->getQtSelectionOwner(), m_net_wm_cm_atom, mask); } } +/*! \internal + + Using _NET_WORKAREA to calculate the available desktop geometry on multi-head systems (systems + with more than one monitor) is unreliable. Different WMs have different interpretations of what + _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 + underlying system. + + One option could be that Qt does WM's job of calculating this by subtracting geometries of + _NET_WM_STRUT_PARTIAL and windows where _NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_DOCK. + But this won't work on Gnome 3 shell as it seems that on this desktop environment the tool panel + is painted directly on the root window. Maybe there is some Gnome/GTK API that could be used + to get height of the panel, but I did not find one. Maybe other WMs have their own tricks, so + the reliability of this approach is questionable. + */ QRect QXcbVirtualDesktop::getWorkArea() const { QRect r; - xcb_get_property_reply_t * workArea = - xcb_get_property_reply(xcb_connection(), - xcb_get_property_unchecked(xcb_connection(), false, screen()->root, - atom(QXcbAtom::_NET_WORKAREA), - XCB_ATOM_CARDINAL, 0, 1024), NULL); + auto workArea = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), false, screen()->root, + atom(QXcbAtom::_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 // (don't mess with QXcbVirtualDesktop which represents an X screen). @@ -142,12 +218,11 @@ QRect QXcbVirtualDesktop::getWorkArea() const // "docked" panel (with _NET_WM_STRUT_PARTIAL atom set) on just one desktop. // But for now just assume the first 4 values give us the geometry of the // "work area", AKA "available geometry" - uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea); + 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()); } - free(workArea); return r; } @@ -167,6 +242,170 @@ static inline QSizeF sizeInMillimeters(const QSize &size, const QDpi &dpi) Q_MM_PER_INCH * size.height() / dpi.second); } +bool QXcbVirtualDesktop::xResource(const QByteArray &identifier, + const QByteArray &expectedIdentifier, + QByteArray& stringValue) +{ + if (identifier.startsWith(expectedIdentifier)) { + stringValue = identifier.mid(expectedIdentifier.size()); + return true; + } + return false; +} + +static bool parseXftInt(const QByteArray& stringValue, int *value) +{ + Q_ASSERT(value != 0); + bool ok; + *value = stringValue.toInt(&ok); + return ok; +} + +static QFontEngine::HintStyle parseXftHintStyle(const QByteArray& stringValue) +{ + if (stringValue == "hintfull") + return QFontEngine::HintFull; + else if (stringValue == "hintnone") + return QFontEngine::HintNone; + else if (stringValue == "hintmedium") + return QFontEngine::HintMedium; + else if (stringValue == "hintslight") + return QFontEngine::HintLight; + + return QFontEngine::HintStyle(-1); +} + +static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stringValue) +{ + if (stringValue == "none") + return QFontEngine::Subpixel_None; + else if (stringValue == "rgb") + return QFontEngine::Subpixel_RGB; + else if (stringValue == "bgr") + return QFontEngine::Subpixel_BGR; + else if (stringValue == "vrgb") + return QFontEngine::Subpixel_VRGB; + else if (stringValue == "vbgr") + return QFontEngine::Subpixel_VBGR; + + return QFontEngine::SubpixelAntialiasingType(-1); +} + +void QXcbVirtualDesktop::readXResources() +{ + int offset = 0; + QByteArray resources; + while (true) { + auto reply = Q_XCB_REPLY_UNCHECKED(xcb_get_property, xcb_connection(), + false, screen()->root, + XCB_ATOM_RESOURCE_MANAGER, + XCB_ATOM_STRING, offset/4, 8192); + bool more = false; + if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) { + resources += QByteArray((const char *)xcb_get_property_value(reply.get()), xcb_get_property_value_length(reply.get())); + offset += xcb_get_property_value_length(reply.get()); + more = reply->bytes_after != 0; + } + + if (!more) + break; + } + + QList<QByteArray> split = resources.split('\n'); + for (int i = 0; i < split.size(); ++i) { + const QByteArray &r = split.at(i); + int value; + QByteArray stringValue; + if (xResource(r, "Xft.dpi:\t", stringValue)) { + if (parseXftInt(stringValue, &value)) + m_forcedDpi = value; + } else if (xResource(r, "Xft.hintstyle:\t", stringValue)) { + m_hintStyle = parseXftHintStyle(stringValue); + } else if (xResource(r, "Xft.antialias:\t", stringValue)) { + if (parseXftInt(stringValue, &value)) + m_antialiasingEnabled = value; + } else if (xResource(r, "Xft.rgba:\t", stringValue)) { + m_subpixelType = parseXftRgba(stringValue); + } + } +} + +QSurfaceFormat QXcbVirtualDesktop::surfaceFormatFor(const QSurfaceFormat &format) const +{ + const xcb_visualid_t xcb_visualid = connection()->hasDefaultVisualId() ? connection()->defaultVisualId() + : screen()->root_visual; + const xcb_visualtype_t *xcb_visualtype = visualForId(xcb_visualid); + + const int redSize = qPopulationCount(xcb_visualtype->red_mask); + const int greenSize = qPopulationCount(xcb_visualtype->green_mask); + const int blueSize = qPopulationCount(xcb_visualtype->blue_mask); + + QSurfaceFormat result = format; + + if (result.redBufferSize() < 0) + result.setRedBufferSize(redSize); + + if (result.greenBufferSize() < 0) + result.setGreenBufferSize(greenSize); + + if (result.blueBufferSize() < 0) + result.setBlueBufferSize(blueSize); + + return result; +} + +const xcb_visualtype_t *QXcbVirtualDesktop::visualForFormat(const QSurfaceFormat &format) const +{ + const xcb_visualtype_t *candidate = nullptr; + + for (const xcb_visualtype_t &xcb_visualtype : m_visuals) { + + const int redSize = qPopulationCount(xcb_visualtype.red_mask); + const int greenSize = qPopulationCount(xcb_visualtype.green_mask); + const int blueSize = qPopulationCount(xcb_visualtype.blue_mask); + const int alphaSize = depthOfVisual(xcb_visualtype.visual_id) - redSize - greenSize - blueSize; + + if (format.redBufferSize() != -1 && redSize != format.redBufferSize()) + continue; + + if (format.greenBufferSize() != -1 && greenSize != format.greenBufferSize()) + continue; + + if (format.blueBufferSize() != -1 && blueSize != format.blueBufferSize()) + continue; + + if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize()) + continue; + + // Try to find a RGB visual rather than e.g. BGR or GBR + if (qCountTrailingZeroBits(xcb_visualtype.blue_mask) == 0) + return &xcb_visualtype; + + // In case we do not find anything we like, just remember the first one + // and hope for the best: + if (!candidate) + candidate = &xcb_visualtype; + } + + return candidate; +} + +const xcb_visualtype_t *QXcbVirtualDesktop::visualForId(xcb_visualid_t visualid) const +{ + QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid); + if (it == m_visuals.constEnd()) + return 0; + return &*it; +} + +quint8 QXcbVirtualDesktop::depthOfVisual(xcb_visualid_t visualid) const +{ + QMap<xcb_visualid_t, quint8>::const_iterator it = m_visualDepths.find(visualid); + if (it == m_visualDepths.constEnd()) + return 0; + return *it; +} + 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) @@ -181,14 +420,11 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe { if (connection->hasXRandr()) { xcb_randr_select_input(xcb_connection(), screen()->root, true); - xcb_randr_get_crtc_info_cookie_t crtcCookie = - xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, output ? output->timestamp : 0); - xcb_randr_get_crtc_info_reply_t *crtc = - xcb_randr_get_crtc_info_reply(xcb_connection(), crtcCookie, NULL); + auto crtc = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_crtc_info, xcb_connection(), + m_crtc, output ? output->timestamp : 0); if (crtc) { updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation); updateRefreshRate(crtc->mode); - free(crtc); } } else if (xineramaScreenInfo) { m_geometry = QRect(xineramaScreenInfo->x_org, xineramaScreenInfo->y_org, @@ -208,74 +444,19 @@ QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDe if (m_sizeMillimeters.isEmpty()) m_sizeMillimeters = m_virtualSizeMillimeters; - readXResources(); - - QScopedPointer<xcb_get_window_attributes_reply_t, QScopedPointerPodDeleter> rootAttribs( - xcb_get_window_attributes_reply(xcb_connection(), - xcb_get_window_attributes_unchecked(xcb_connection(), screen()->root), NULL)); - const quint32 existingEventMask = rootAttribs.isNull() ? 0 : rootAttribs->your_event_mask; - - const quint32 mask = XCB_CW_EVENT_MASK; - const quint32 values[] = { - // XCB_CW_EVENT_MASK - XCB_EVENT_MASK_ENTER_WINDOW - | XCB_EVENT_MASK_LEAVE_WINDOW - | XCB_EVENT_MASK_PROPERTY_CHANGE - | XCB_EVENT_MASK_STRUCTURE_NOTIFY // for the "MANAGER" atom (system tray notification). - | existingEventMask // don't overwrite the event mask on the root window - }; - - xcb_change_window_attributes(xcb_connection(), screen()->root, mask, values); - - xcb_get_property_reply_t *reply = - xcb_get_property_reply(xcb_connection(), - xcb_get_property_unchecked(xcb_connection(), false, screen()->root, - atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK), - XCB_ATOM_WINDOW, 0, 1024), NULL); - - if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) { - xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply)); - - if (windowManager != XCB_WINDOW_NONE) { - xcb_get_property_reply_t *windowManagerReply = - xcb_get_property_reply(xcb_connection(), - xcb_get_property_unchecked(xcb_connection(), false, windowManager, - atom(QXcbAtom::_NET_WM_NAME), - atom(QXcbAtom::UTF8_STRING), 0, 1024), NULL); - if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) { - m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply)); - } - - free(windowManagerReply); - } - } - free(reply); + m_cursor = new QXcbCursor(connection, this); - const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id); - if (!sync_reply || !sync_reply->present) - m_syncRequestSupported = false; + // Parse EDID + if (m_edid.parse(getEdid())) + qCDebug(lcQpaScreen, "EDID data for output \"%s\": identifier '%s', manufacturer '%s', model '%s', serial '%s', physical size: %.2fx%.2f", + name().toLatin1().constData(), + m_edid.identifier.toLatin1().constData(), + m_edid.manufacturer.toLatin1().constData(), + m_edid.model.toLatin1().constData(), + m_edid.serialNumber.toLatin1().constData(), + m_edid.physicalSize.width(), m_edid.physicalSize.height()); else - m_syncRequestSupported = true; - - xcb_depth_iterator_t depth_iterator = - xcb_screen_allowed_depths_iterator(screen()); - - while (depth_iterator.rem) { - xcb_depth_t *depth = depth_iterator.data; - xcb_visualtype_iterator_t visualtype_iterator = - xcb_depth_visuals_iterator(depth); - - while (visualtype_iterator.rem) { - xcb_visualtype_t *visualtype = visualtype_iterator.data; - m_visuals.insert(visualtype->visual_id, *visualtype); - m_visualDepths.insert(visualtype->visual_id, depth->depth); - xcb_visualtype_next(&visualtype_iterator); - } - - xcb_depth_next(&depth_iterator); - } - - m_cursor = new QXcbCursor(connection, this); + qCDebug(lcQpaScreen) << "Failed to parse EDID data for output" << name(); // keep this debug, not warning } QXcbScreen::~QXcbScreen() @@ -300,6 +481,21 @@ QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo) return name; } +QString QXcbScreen::manufacturer() const +{ + return m_edid.manufacturer; +} + +QString QXcbScreen::model() const +{ + return m_edid.model; +} + +QString QXcbScreen::serialNumber() const +{ + return m_edid.serialNumber; +} + QWindow *QXcbScreen::topLevelAt(const QPoint &p) const { xcb_window_t root = screen()->root; @@ -311,12 +507,7 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const xcb_window_t child = root; do { - xcb_translate_coordinates_cookie_t translate_cookie = - xcb_translate_coordinates_unchecked(xcb_connection(), parent, child, x, y); - - xcb_translate_coordinates_reply_t *translate_reply = - xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, NULL); - + auto translate_reply = Q_XCB_REPLY_UNCHECKED(xcb_translate_coordinates, xcb_connection(), parent, child, x, y); if (!translate_reply) { return 0; } @@ -326,8 +517,6 @@ QWindow *QXcbScreen::topLevelAt(const QPoint &p) const x = translate_reply->dst_x; y = translate_reply->dst_y; - free(translate_reply); - if (!child || child == root) return 0; @@ -350,62 +539,12 @@ void QXcbScreen::windowShown(QXcbWindow *window) QSurfaceFormat QXcbScreen::surfaceFormatFor(const QSurfaceFormat &format) const { - const xcb_visualid_t xcb_visualid = connection()->hasDefaultVisualId() ? connection()->defaultVisualId() - : screen()->root_visual; - const xcb_visualtype_t *xcb_visualtype = visualForId(xcb_visualid); - - const int redSize = qPopulationCount(xcb_visualtype->red_mask); - const int greenSize = qPopulationCount(xcb_visualtype->green_mask); - const int blueSize = qPopulationCount(xcb_visualtype->blue_mask); - - QSurfaceFormat result = format; - - if (result.redBufferSize() < 0) - result.setRedBufferSize(redSize); - - if (result.greenBufferSize() < 0) - result.setGreenBufferSize(greenSize); - - if (result.blueBufferSize() < 0) - result.setBlueBufferSize(blueSize); - - return result; + return m_virtualDesktop->surfaceFormatFor(format); } -const xcb_visualtype_t *QXcbScreen::visualForFormat(const QSurfaceFormat &format) const +const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const { - const xcb_visualtype_t *candidate = nullptr; - - for (const xcb_visualtype_t &xcb_visualtype : m_visuals) { - - const int redSize = qPopulationCount(xcb_visualtype.red_mask); - const int greenSize = qPopulationCount(xcb_visualtype.green_mask); - const int blueSize = qPopulationCount(xcb_visualtype.blue_mask); - const int alphaSize = depthOfVisual(xcb_visualtype.visual_id) - redSize - greenSize - blueSize; - - if (format.redBufferSize() != -1 && redSize != format.redBufferSize()) - continue; - - if (format.greenBufferSize() != -1 && greenSize != format.greenBufferSize()) - continue; - - if (format.blueBufferSize() != -1 && blueSize != format.blueBufferSize()) - continue; - - if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize()) - continue; - - // Try to find a RGB visual rather than e.g. BGR or GBR - if (qCountTrailingZeroBits(xcb_visualtype.blue_mask) == 0) - return &xcb_visualtype; - - // In case we do not find anything we like, just remember the first one - // and hope for the best: - if (!candidate) - candidate = &xcb_visualtype; - } - - return candidate; + return m_virtualDesktop->visualForId(visualid); } void QXcbScreen::sendStartupMessage(const QByteArray &message) const @@ -434,20 +573,12 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const } while (sent < length); } -const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const +QRect QXcbScreen::availableGeometry() const { - QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid); - if (it == m_visuals.constEnd()) - return 0; - return &*it; -} - -quint8 QXcbScreen::depthOfVisual(xcb_visualid_t visualid) const -{ - QMap<xcb_visualid_t, quint8>::const_iterator it = m_visualDepths.find(visualid); - if (it == m_visualDepths.constEnd()) - return 0; - return *it; + static bool enforceNetWorkarea = !qEnvironmentVariableIsEmpty("QT_RELY_ON_NET_WORKAREA_ATOM"); + bool isMultiHeadSystem = virtualSiblings().length() > 1; + bool useScreenGeometry = isMultiHeadSystem && !enforceNetWorkarea; + return useScreenGeometry ? m_geometry : m_availableGeometry; } QImage::Format QXcbScreen::format() const @@ -468,8 +599,9 @@ QDpi QXcbScreen::logicalDpi() const if (overrideDpi) return QDpi(overrideDpi, overrideDpi); - if (m_forcedDpi > 0) { - return QDpi(m_forcedDpi, m_forcedDpi); + const int forcedDpi = m_virtualDesktop->forcedDpi(); + if (forcedDpi > 0) { + return QDpi(forcedDpi, forcedDpi); } return virtualDpi(); } @@ -581,19 +713,14 @@ void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp) if (!connection()->hasXRandr()) return; - xcb_randr_get_crtc_info_cookie_t crtcCookie = - xcb_randr_get_crtc_info_unchecked(xcb_connection(), m_crtc, timestamp); - xcb_randr_get_crtc_info_reply_t *crtc = - xcb_randr_get_crtc_info_reply(xcb_connection(), crtcCookie, NULL); - if (crtc) { + auto crtc = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_crtc_info, xcb_connection(), + m_crtc, timestamp); + if (crtc) updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation); - free(crtc); - } } -void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation) +void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation) { - QRect xGeometry = geom; switch (rotation) { case XCB_RANDR_ROTATION_ROTATE_0: // xrandr --rotate normal m_orientation = Qt::LandscapeOrientation; @@ -617,12 +744,12 @@ void QXcbScreen::updateGeometry(const QRect &geom, uint8_t rotation) // is known (probably back-calculated from DPI and resolution), // e.g. on VNC or with some hardware. if (m_sizeMillimeters.isEmpty()) - m_sizeMillimeters = sizeInMillimeters(xGeometry.size(), virtualDpi()); + m_sizeMillimeters = sizeInMillimeters(geometry.size(), virtualDpi()); - qreal dpi = xGeometry.width() / physicalSize().width() * qreal(25.4); + qreal dpi = geometry.width() / physicalSize().width() * qreal(25.4); m_pixelDensity = qMax(1, qRound(dpi/96)); - m_geometry = QRect(xGeometry.topLeft(), xGeometry.size()); - m_availableGeometry = xGeometry & m_virtualDesktop->workArea(); + m_geometry = geometry; + m_availableGeometry = geometry & m_virtualDesktop->workArea(); QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry); } @@ -645,13 +772,11 @@ void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode) // we can safely use get_screen_resources_current here, because in order to // get here, we must have called get_screen_resources before - xcb_randr_get_screen_resources_current_cookie_t resourcesCookie = - xcb_randr_get_screen_resources_current_unchecked(xcb_connection(), screen()->root); - xcb_randr_get_screen_resources_current_reply_t *resources = - xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, NULL); + auto resources = Q_XCB_REPLY_UNCHECKED(xcb_randr_get_screen_resources_current, + xcb_connection(), screen()->root); if (resources) { xcb_randr_mode_info_iterator_t modesIter = - xcb_randr_get_screen_resources_current_modes_iterator(resources); + xcb_randr_get_screen_resources_current_modes_iterator(resources.get()); for (; modesIter.rem; xcb_randr_mode_info_next(&modesIter)) { xcb_randr_mode_info_t *modeInfo = modesIter.data; if (modeInfo->id == mode) { @@ -662,29 +787,19 @@ void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode) } } - free(resources); QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), m_refreshRate); } } -static xcb_get_geometry_reply_t *getGeometryUnchecked(xcb_connection_t *connection, xcb_window_t window) -{ - const xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry_unchecked(connection, window); - return xcb_get_geometry_reply(connection, geometry_cookie, NULL); -} - static inline bool translate(xcb_connection_t *connection, xcb_window_t child, xcb_window_t parent, int *x, int *y) { - const xcb_translate_coordinates_cookie_t translate_cookie = - xcb_translate_coordinates_unchecked(connection, child, parent, *x, *y); - xcb_translate_coordinates_reply_t *translate_reply = - xcb_translate_coordinates_reply(connection, translate_cookie, NULL); + auto translate_reply = Q_XCB_REPLY_UNCHECKED(xcb_translate_coordinates, + connection, child, parent, *x, *y); if (!translate_reply) return false; *x = translate_reply->dst_x; *y = translate_reply->dst_y; - free(translate_reply); return true; } @@ -698,22 +813,20 @@ QPixmap QXcbScreen::grabWindow(WId window, int xIn, int yIn, int width, int heig QXcbScreen *screen = const_cast<QXcbScreen *>(this); xcb_window_t root = screen->root(); - xcb_get_geometry_reply_t *rootReply = getGeometryUnchecked(xcb_connection(), root); + auto rootReply = Q_XCB_REPLY_UNCHECKED(xcb_get_geometry, xcb_connection(), root); if (!rootReply) return QPixmap(); const quint8 rootDepth = rootReply->depth; - free(rootReply); QSize windowSize; quint8 effectiveDepth = 0; if (window) { - xcb_get_geometry_reply_t *windowReply = getGeometryUnchecked(xcb_connection(), window); + auto windowReply = Q_XCB_REPLY_UNCHECKED(xcb_get_geometry, xcb_connection(), window); if (!windowReply) return QPixmap(); windowSize = QSize(windowReply->width, windowReply->height); effectiveDepth = windowReply->depth; - free(windowReply); if (effectiveDepth == rootDepth) { // if the depth of the specified window and the root window are the // same, grab pixels from the root window (so that we get the any @@ -738,14 +851,12 @@ QPixmap QXcbScreen::grabWindow(WId window, int xIn, int yIn, int width, int heig if (height < 0) height = windowSize.height() - yIn; - xcb_get_window_attributes_reply_t *attributes_reply = - xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), window), NULL); + auto attributes_reply = Q_XCB_REPLY_UNCHECKED(xcb_get_window_attributes, xcb_connection(), window); if (!attributes_reply) return QPixmap(); const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual); - free(attributes_reply); xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection()); xcb_create_pixmap(xcb_connection(), effectiveDepth, pixmap, window, width, height); @@ -765,101 +876,41 @@ QPixmap QXcbScreen::grabWindow(WId window, int xIn, int yIn, int width, int heig return result; } -static bool parseXftInt(const QByteArray& stringValue, int *value) +QXcbXSettings *QXcbScreen::xSettings() const { - Q_ASSERT(value != 0); - bool ok; - *value = stringValue.toInt(&ok); - return ok; + return m_virtualDesktop->xSettings(); } -static QFontEngine::HintStyle parseXftHintStyle(const QByteArray& stringValue) +QByteArray QXcbScreen::getOutputProperty(xcb_atom_t atom) const { - if (stringValue == "hintfull") - return QFontEngine::HintFull; - else if (stringValue == "hintnone") - return QFontEngine::HintNone; - else if (stringValue == "hintmedium") - return QFontEngine::HintMedium; - else if (stringValue == "hintslight") - return QFontEngine::HintLight; - - return QFontEngine::HintStyle(-1); -} + QByteArray result; -static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray& stringValue) -{ - if (stringValue == "none") - return QFontEngine::Subpixel_None; - else if (stringValue == "rgb") - return QFontEngine::Subpixel_RGB; - else if (stringValue == "bgr") - return QFontEngine::Subpixel_BGR; - else if (stringValue == "vrgb") - return QFontEngine::Subpixel_VRGB; - else if (stringValue == "vbgr") - return QFontEngine::Subpixel_VBGR; + auto reply = Q_XCB_REPLY(xcb_randr_get_output_property, xcb_connection(), + m_output, atom, XCB_ATOM_ANY, 0, 100, false, false); + if (reply && reply->type == XCB_ATOM_INTEGER && reply->format == 8) { + quint8 *data = new quint8[reply->num_items]; + memcpy(data, xcb_randr_get_output_property_data(reply.get()), reply->num_items); + result = QByteArray(reinterpret_cast<const char *>(data), reply->num_items); + delete[] data; + } - return QFontEngine::SubpixelAntialiasingType(-1); + return result; } -bool QXcbScreen::xResource(const QByteArray &identifier, - const QByteArray &expectedIdentifier, - QByteArray& stringValue) +QByteArray QXcbScreen::getEdid() const { - if (identifier.startsWith(expectedIdentifier)) { - stringValue = identifier.mid(expectedIdentifier.size()); - return true; + // Try a bunch of atoms + xcb_atom_t atom = connection()->internAtom("EDID"); + QByteArray result = getOutputProperty(atom); + if (result.isEmpty()) { + atom = connection()->internAtom("EDID_DATA"); + result = getOutputProperty(atom); } - return false; -} - -void QXcbScreen::readXResources() -{ - int offset = 0; - QByteArray resources; - while(1) { - xcb_get_property_reply_t *reply = - xcb_get_property_reply(xcb_connection(), - xcb_get_property_unchecked(xcb_connection(), false, screen()->root, - XCB_ATOM_RESOURCE_MANAGER, - XCB_ATOM_STRING, offset/4, 8192), NULL); - bool more = false; - if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) { - resources += QByteArray((const char *)xcb_get_property_value(reply), xcb_get_property_value_length(reply)); - offset += xcb_get_property_value_length(reply); - more = reply->bytes_after != 0; - } - - if (reply) - free(reply); - - if (!more) - break; + if (result.isEmpty()) { + atom = connection()->internAtom("XFree86_DDC_EDID1_RAWDATA"); + result = getOutputProperty(atom); } - - QList<QByteArray> split = resources.split('\n'); - for (int i = 0; i < split.size(); ++i) { - const QByteArray &r = split.at(i); - int value; - QByteArray stringValue; - if (xResource(r, "Xft.dpi:\t", stringValue)) { - if (parseXftInt(stringValue, &value)) - m_forcedDpi = value; - } else if (xResource(r, "Xft.hintstyle:\t", stringValue)) { - m_hintStyle = parseXftHintStyle(stringValue); - } else if (xResource(r, "Xft.antialias:\t", stringValue)) { - if (parseXftInt(stringValue, &value)) - m_antialiasingEnabled = value; - } else if (xResource(r, "Xft.rgba:\t", stringValue)) { - m_subpixelType = parseXftRgba(stringValue); - } - } -} - -QXcbXSettings *QXcbScreen::xSettings() const -{ - return m_virtualDesktop->xSettings(); + return result; } static inline void formatRect(QDebug &debug, const QRect r) |