15#include <QtAlgorithms>
17#include <qpa/qwindowsysteminterface.h>
18#include <private/qmath_p.h>
22QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t *screen,
int number)
23 : QXcbObject(connection)
26 , m_xSettings(
new QXcbXSettings(
this))
28 const QByteArray cmAtomName =
"_NET_WM_CM_S" + QByteArray::number(m_number);
29 m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
30 m_compositingActive = connection->selectionOwner(m_net_wm_cm_atom);
32 m_workArea = getWorkArea();
38 const quint32 existingEventMask = !rootAttribs ? 0 : rootAttribs->your_event_mask;
40 const quint32 mask = XCB_CW_EVENT_MASK;
41 const quint32 values[] = {
43 XCB_EVENT_MASK_ENTER_WINDOW
44 | XCB_EVENT_MASK_LEAVE_WINDOW
45 | XCB_EVENT_MASK_PROPERTY_CHANGE
46 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
50 xcb_change_window_attributes(xcb_connection(), screen->root, mask, values);
54 atom(QXcbAtom::Atom_NET_SUPPORTING_WM_CHECK),
55 XCB_ATOM_WINDOW, 0, 1024);
56 if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
57 xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply.get()));
59 if (windowManager != XCB_WINDOW_NONE)
60 m_windowManagerName = QXcbWindow::windowTitle(connection, windowManager);
63 xcb_depth_iterator_t depth_iterator =
64 xcb_screen_allowed_depths_iterator(screen);
66 while (depth_iterator.rem) {
67 xcb_depth_t *depth = depth_iterator.data;
68 xcb_visualtype_iterator_t visualtype_iterator =
69 xcb_depth_visuals_iterator(depth);
71 while (visualtype_iterator.rem) {
72 xcb_visualtype_t *visualtype = visualtype_iterator.data;
73 m_visuals.insert(visualtype->visual_id, *visualtype);
74 m_visualDepths.insert(visualtype->visual_id, depth->depth);
75 xcb_visualtype_next(&visualtype_iterator);
78 xcb_depth_next(&depth_iterator);
81 auto dpiChangedCallback = [](QXcbVirtualDesktop *desktop,
const QByteArray &,
const QVariant &property,
void *) {
82 if (!desktop->setDpiFromXSettings(property))
84 const auto dpi = desktop->forcedDpi();
85 for (QXcbScreen *screen : desktop->connection()->screens())
86 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->QPlatformScreen::screen(), dpi, dpi);
88 setDpiFromXSettings(xSettings()->setting(
"Xft/DPI"));
89 xSettings()->registerCallbackForProperty(
"Xft/DPI", dpiChangedCallback,
nullptr);
96 for (
auto cmap : std::as_const(m_visualColormaps))
97 xcb_free_colormap(xcb_connection(), cmap);
102 const QSize virtualSize = size();
103 const QSize virtualSizeMillimeters = physicalSize();
105 return QDpi(Q_MM_PER_INCH * virtualSize.width() / virtualSizeMillimeters.width(),
106 Q_MM_PER_INCH * virtualSize.height() / virtualSizeMillimeters.height());
112 for (QXcbScreen *screen : screens) {
113 if (screen->virtualDesktop() ==
this && screen->geometry().contains(pos))
121 ((QXcbScreen *) s)->isPrimary() ? m_screens.prepend(s) : m_screens.append(s);
126 const int idx = m_screens.indexOf(s);
128 m_screens.swapItemsAt(0, idx);
139 return m_compositingActive;
141 return connection()->selectionOwner(m_net_wm_cm_atom);
146 if (notify_event->selection == m_net_wm_cm_atom)
147 m_compositingActive = notify_event->owner;
153 const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
154 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
155 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
156 xcb_xfixes_select_selection_input_checked(
xcb_connection(),
connection()->qtSelectionOwner(), m_net_wm_cm_atom, mask);
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
187 if (change_event->rotation == m_rotation)
190 m_rotation = change_event->rotation;
191 switch (m_rotation) {
192 case XCB_RANDR_ROTATION_ROTATE_0:
193 m_screen->width_in_pixels = change_event->width;
194 m_screen->height_in_pixels = change_event->height;
195 m_screen->width_in_millimeters = change_event->mwidth;
196 m_screen->height_in_millimeters = change_event->mheight;
198 case XCB_RANDR_ROTATION_ROTATE_90:
199 m_screen->width_in_pixels = change_event->height;
200 m_screen->height_in_pixels = change_event->width;
201 m_screen->width_in_millimeters = change_event->mheight;
202 m_screen->height_in_millimeters = change_event->mwidth;
204 case XCB_RANDR_ROTATION_ROTATE_180:
205 m_screen->width_in_pixels = change_event->width;
206 m_screen->height_in_pixels = change_event->height;
207 m_screen->width_in_millimeters = change_event->mwidth;
208 m_screen->height_in_millimeters = change_event->mheight;
210 case XCB_RANDR_ROTATION_ROTATE_270:
211 m_screen->width_in_pixels = change_event->height;
212 m_screen->height_in_pixels = change_event->width;
213 m_screen->width_in_millimeters = change_event->mheight;
214 m_screen->height_in_millimeters = change_event->mwidth;
218 case XCB_RANDR_ROTATION_REFLECT_X:
break;
219 case XCB_RANDR_ROTATION_REFLECT_Y:
break;
222 for (QPlatformScreen *platformScreen : std::as_const(m_screens)) {
223 QDpi ldpi = platformScreen->logicalDpi();
224 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(platformScreen->screen(), ldpi.first, ldpi.second);
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
249 atom(QXcbAtom::Atom_NET_WORKAREA),
250 XCB_ATOM_CARDINAL, 0, 1024);
251 if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
258 uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea.get());
259 r = QRect(geom[0], geom[1], geom[2], geom[3]);
268 QRect workArea = getWorkArea();
269 if (m_workArea != workArea) {
270 m_workArea = workArea;
271 for (QPlatformScreen *screen : std::as_const(m_screens))
272 ((QXcbScreen *)screen)->updateAvailableGeometry();
278 return m_workArea.width() >= 0 ? screenGeometry & m_workArea : screenGeometry;
283 return QSizeF(Q_MM_PER_INCH * size.width() / dpi.first,
284 Q_MM_PER_INCH * size.height() / dpi.second);
288 const QByteArray &expectedIdentifier,
289 QByteArray& stringValue)
291 if (identifier.startsWith(expectedIdentifier)) {
292 stringValue = identifier.mid(expectedIdentifier.size());
302 *value = stringValue.toInt(&ok);
309 bool ok = parseXftInt(stringValue, value);
312 *value = qRound(stringValue.toDouble(&ok));
318 if (stringValue ==
"hintfull")
319 return QFontEngine::HintFull;
320 else if (stringValue ==
"hintnone")
321 return QFontEngine::HintNone;
322 else if (stringValue ==
"hintmedium")
323 return QFontEngine::HintMedium;
324 else if (stringValue ==
"hintslight")
325 return QFontEngine::HintLight;
327 return QFontEngine::HintStyle(-1);
332 if (stringValue ==
"none")
333 return QFontEngine::Subpixel_None;
334 else if (stringValue ==
"rgb")
335 return QFontEngine::Subpixel_RGB;
336 else if (stringValue ==
"bgr")
337 return QFontEngine::Subpixel_BGR;
338 else if (stringValue ==
"vrgb")
339 return QFontEngine::Subpixel_VRGB;
340 else if (stringValue ==
"vbgr")
341 return QFontEngine::Subpixel_VBGR;
343 return QFontEngine::SubpixelAntialiasingType(-1);
349 QByteArray resources;
352 false, screen()->root,
353 XCB_ATOM_RESOURCE_MANAGER,
354 XCB_ATOM_STRING, offset/4, 8192);
356 if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) {
357 resources += QByteArray((
const char *)xcb_get_property_value(reply.get()), xcb_get_property_value_length(reply.get()));
358 offset += xcb_get_property_value_length(reply.get());
359 more = reply->bytes_after != 0;
366 QList<QByteArray> split = resources.split(
'\n');
367 for (
int i = 0; i < split.size(); ++i) {
368 const QByteArray &r = split.at(i);
370 QByteArray stringValue;
371 if (xResource(r,
"Xft.dpi:\t", stringValue)) {
372 if (parseXftDpi(stringValue, &value))
374 }
else if (xResource(r,
"Xft.hintstyle:\t", stringValue)) {
375 m_hintStyle = parseXftHintStyle(stringValue);
376 }
else if (xResource(r,
"Xft.antialias:\t", stringValue)) {
377 if (parseXftInt(stringValue, &value))
378 m_antialiasingEnabled = value;
379 }
else if (xResource(r,
"Xft.rgba:\t", stringValue)) {
380 m_subpixelType = parseXftRgba(stringValue);
388 int dpiTimes1k = property.toInt(&ok);
391 int dpi = dpiTimes1k / 1024;
392 if (m_forcedDpi == dpi)
400 const xcb_visualid_t xcb_visualid =
connection()->hasDefaultVisualId() ?
connection()->defaultVisualId()
402 const xcb_visualtype_t *xcb_visualtype =
visualForId(xcb_visualid
);
404 const int redSize = qPopulationCount(xcb_visualtype->red_mask);
405 const int greenSize = qPopulationCount(xcb_visualtype->green_mask);
406 const int blueSize = qPopulationCount(xcb_visualtype->blue_mask);
408 QSurfaceFormat result = format;
410 if (result.redBufferSize() < 0)
411 result.setRedBufferSize(redSize);
413 if (result.greenBufferSize() < 0)
414 result.setGreenBufferSize(greenSize);
416 if (result.blueBufferSize() < 0)
417 result.setBlueBufferSize(blueSize);
424 const xcb_visualtype_t *candidate =
nullptr;
426 for (
const xcb_visualtype_t &xcb_visualtype : m_visuals) {
428 const int redSize = qPopulationCount(xcb_visualtype.red_mask);
429 const int greenSize = qPopulationCount(xcb_visualtype.green_mask);
430 const int blueSize = qPopulationCount(xcb_visualtype.blue_mask);
431 const int alphaSize = depthOfVisual(xcb_visualtype.visual_id) - redSize - greenSize - blueSize;
433 if (format.redBufferSize() != -1 && redSize != format.redBufferSize())
436 if (format.greenBufferSize() != -1 && greenSize != format.greenBufferSize())
439 if (format.blueBufferSize() != -1 && blueSize != format.blueBufferSize())
442 if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize())
446 if (qCountTrailingZeroBits(xcb_visualtype.blue_mask) == 0)
447 return &xcb_visualtype;
452 candidate = &xcb_visualtype;
460 QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
461 if (it == m_visuals.constEnd())
468 QMap<xcb_visualid_t, quint8>::const_iterator it = m_visualDepths.find(visualid);
469 if (it == m_visualDepths.constEnd())
476 auto it = m_visualColormaps.constFind(visualid);
477 if (it != m_visualColormaps.constEnd())
482 XCB_COLORMAP_ALLOC_NONE,
486 m_visualColormaps.insert(visualid, cmap);
490QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
491 xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output)
492 : QXcbObject(connection)
493 , m_virtualDesktop(virtualDesktop)
496 , m_crtc(output ? output->crtc : XCB_NONE)
497 , m_outputName(getOutputName(output))
498 , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
499 , m_cursor(std::make_unique<QXcbCursor>(connection,
this))
501 if (connection->isAtLeastXRandR12()) {
503 m_crtc, output ? output->timestamp : 0);
505 updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
506 updateRefreshRate(crtc->mode);
510 if (m_geometry.isEmpty())
511 m_geometry = QRect(QPoint(), virtualDesktop->size());
513 if (m_availableGeometry.isEmpty())
514 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
516 if (m_sizeMillimeters.isEmpty())
517 m_sizeMillimeters = virtualDesktop->physicalSize();
519 updateColorSpaceAndEdid();
522void QXcbScreen::updateColorSpaceAndEdid()
527 false, screen()->root,
528 connection()->atom(QXcbAtom::Atom_ICC_PROFILE),
529 XCB_ATOM_CARDINAL, 0, 8192);
530 if (reply->format == 8 && reply->type == XCB_ATOM_CARDINAL) {
531 QByteArray data(
reinterpret_cast<
const char *>(xcb_get_property_value(reply.get())), reply->value_len);
532 m_colorSpace = QColorSpace::fromIccProfile(data);
535 if (connection()->isAtLeastXRandR12()) {
536 QByteArray edid = getEdid();
537 if (m_edid.parse(edid)) {
538 qCDebug(lcQpaScreen,
"EDID data for output \"%s\": identifier '%s', manufacturer '%s',"
539 "model '%s', serial '%s', physical size: %.2fx%.2f",
540 name().toLatin1().constData(),
541 m_edid.identifier.toLatin1().constData(),
542 m_edid.manufacturer.toLatin1().constData(),
543 m_edid.model.toLatin1().constData(),
544 m_edid.serialNumber.toLatin1().constData(),
545 m_edid.physicalSize.width(), m_edid.physicalSize.height());
546 if (!m_colorSpace.isValid()) {
548 m_colorSpace = QColorSpace::SRgb;
550 if (!m_edid.useTables) {
551 m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
552 m_edid.greenChromaticity, m_edid.blueChromaticity,
553 QColorSpace::TransferFunction::Gamma, m_edid.gamma);
555 if (m_edid.tables.size() == 1) {
556 m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
557 m_edid.greenChromaticity, m_edid.blueChromaticity,
559 }
else if (m_edid.tables.size() == 3) {
560 m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
561 m_edid.greenChromaticity, m_edid.blueChromaticity,
562 m_edid.tables[0], m_edid.tables[1], m_edid.tables[2]);
570 qCDebug(lcQpaScreen) <<
"Failed to parse EDID data for output" << name() <<
571 "edid data: " << edid;
574 if (!m_colorSpace.isValid())
575 m_colorSpace = QColorSpace::SRgb;
578QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
579 xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
580 : QXcbObject(connection)
581 , m_virtualDesktop(virtualDesktop)
582 , m_monitor(monitorInfo)
583 , m_cursor(std::make_unique<QXcbCursor>(connection,
this))
585 setMonitor(monitorInfo, timestamp);
588void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
590 if (!connection()->isAtLeastXRandR15())
597 m_singlescreen =
false;
602 m_outputName = defaultName();
607 m_monitor = monitorInfo;
608 qCDebug(lcQpaScreen) <<
"xcb_randr_monitor_info_t: primary=" << m_monitor->primary <<
", x=" << m_monitor->x <<
", y=" << m_monitor->y
609 <<
", width=" << m_monitor->width <<
", height=" << m_monitor->height
610 <<
", width_in_millimeters=" << m_monitor->width_in_millimeters <<
", height_in_millimeters=" << m_monitor->height_in_millimeters;
611 QRect monitorGeometry = QRect(m_monitor->x, m_monitor->y,
612 m_monitor->width, m_monitor->height);
613 m_sizeMillimeters = QSize(m_monitor->width_in_millimeters, m_monitor->height_in_millimeters);
615 int outputCount = xcb_randr_monitor_info_outputs_length(m_monitor);
616 xcb_randr_output_t *outputs =
nullptr;
618 outputs = xcb_randr_monitor_info_outputs(m_monitor);
619 for (
int i = 0; i < outputCount; i++) {
621 xcb_connection(), outputs[i], timestamp);
626 if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
627 qCDebug(lcQpaScreen,
"Output %s is not connected", qPrintable(
628 QString::fromUtf8((
const char*)xcb_randr_get_output_info_name(output.get()),
629 xcb_randr_get_output_info_name_length(output.get()))));
633 if (output->crtc == XCB_NONE) {
634 qCDebug(lcQpaScreen,
"Output %s is not enabled", qPrintable(
635 QString::fromUtf8((
const char*)xcb_randr_get_output_info_name(output.get()),
636 xcb_randr_get_output_info_name_length(output.get()))));
640 m_outputs << outputs[i];
641 if (m_output == XCB_NONE) {
642 m_output = outputs[i];
643 m_outputSizeMillimeters = QSize(output->mm_width, output->mm_height);
645 m_crtcs << output->crtc;
646 if (m_crtc == XCB_NONE)
647 m_crtc = output->crtc;
651 if (m_crtcs.size() == 1) {
653 xcb_connection(), m_crtcs[0], timestamp);
654 if (crtc == XCB_NONE) {
655 qCDebug(lcQpaScreen,
"Didn't get crtc info when m_crtcs.size() == 1");
657 m_singlescreen = (monitorGeometry == (QRect(crtc->x, crtc->y, crtc->width, crtc->height)));
658 if (m_singlescreen) {
660 updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
661 if (mode() != crtc->mode)
662 updateRefreshRate(crtc->mode);
669 m_geometry = monitorGeometry;
670 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
671 if (m_geometry.isEmpty())
672 m_geometry = QRect(QPoint(), virtualDesktop()->size());
673 if (m_availableGeometry.isEmpty())
674 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
676 if (m_sizeMillimeters.isEmpty())
677 m_sizeMillimeters = virtualDesktop()->physicalSize();
679 m_outputName = getName(monitorInfo);
681 if (connection()->primaryScreenNumber() == virtualDesktop()->number()) {
682 if (monitorInfo->primary || isPrimaryInXScreen())
686 updateColorSpaceAndEdid();
689QString QXcbScreen::defaultName()
692 QByteArray displayName = connection()->displayName();
693 int dotPos = displayName.lastIndexOf(
'.');
695 displayName.truncate(dotPos);
696 name = QString::fromLocal8Bit(displayName) + u'.'
697 + QString::number(m_virtualDesktop->number());
701bool QXcbScreen::isPrimaryInXScreen()
703 auto primary =
Q_XCB_REPLY(xcb_randr_get_output_primary, connection()->xcb_connection(), root());
705 qWarning(
"failed to get the primary output of the screen");
707 const bool isPrimary = primary ? (m_monitor ? m_outputs.contains(primary->output) : m_output == primary->output) :
false;
712QXcbScreen::~QXcbScreen()
716QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
720 name = QString::fromUtf8((
const char*)xcb_randr_get_output_info_name(outputInfo),
721 xcb_randr_get_output_info_name_length(outputInfo));
723 name = defaultName();
728QString QXcbScreen::getName(xcb_randr_monitor_info_t *monitorInfo)
731 QByteArray ba = connection()->atomName(monitorInfo->name);
733 name = QString::fromLatin1(ba.constData());
735 QByteArray displayName = connection()->displayName();
736 int dotPos = displayName.lastIndexOf(
'.');
738 displayName.truncate(dotPos);
739 name = QString::fromLocal8Bit(displayName) + u'.'
740 + QString::number(m_virtualDesktop->number());
745QString QXcbScreen::manufacturer()
const
747 return m_edid.manufacturer;
750QString QXcbScreen::model()
const
755QString QXcbScreen::serialNumber()
const
757 return m_edid.serialNumber;
760QWindow *QXcbScreen::topLevelAt(
const QPoint &p)
const
762 xcb_window_t root = screen()->root;
767 xcb_window_t parent = root;
768 xcb_window_t child = root;
771 auto translate_reply =
Q_XCB_REPLY_UNCHECKED(xcb_translate_coordinates, xcb_connection(), parent, child, x, y);
772 if (!translate_reply) {
777 child = translate_reply->child;
778 x = translate_reply->dst_x;
779 y = translate_reply->dst_y;
781 if (!child || child == root)
784 QPlatformWindow *platformWindow = connection()->platformWindowFromId(child);
786 return platformWindow->window();
787 }
while (parent != child);
792void QXcbScreen::windowShown(QXcbWindow *window)
795 if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) {
796 sendStartupMessage(QByteArrayLiteral(
"remove: ID=") + connection()->startupId());
797 connection()->setStartupId({});
801QSurfaceFormat QXcbScreen::surfaceFormatFor(
const QSurfaceFormat &format)
const
803 return m_virtualDesktop->surfaceFormatFor(format);
806const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid)
const
808 return m_virtualDesktop->visualForId(visualid);
811void QXcbScreen::sendStartupMessage(
const QByteArray &message)
const
813 xcb_window_t rootWindow = root();
815 xcb_client_message_event_t ev;
816 ev.response_type = XCB_CLIENT_MESSAGE;
818 ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO_BEGIN);
820 ev.window = rootWindow;
822 int length = message.size() + 1;
823 const char *data = message.constData();
826 ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO);
828 const int start = sent;
829 const int numBytes = qMin(length - start, 20);
830 memcpy(ev.data.data8, data + start, numBytes);
831 xcb_send_event(connection()->xcb_connection(),
false, rootWindow, XCB_EVENT_MASK_PROPERTY_CHANGE, (
const char *) &ev);
834 }
while (sent < length);
837QRect QXcbScreen::availableGeometry()
const
839 static bool enforceNetWorkarea = !qEnvironmentVariableIsEmpty(
"QT_RELY_ON_NET_WORKAREA_ATOM");
840 bool isMultiHeadSystem = virtualSiblings().size() > 1;
841 bool useScreenGeometry = isMultiHeadSystem && !enforceNetWorkarea;
842 return useScreenGeometry ? m_geometry : m_availableGeometry;
845QImage::Format QXcbScreen::format()
const
847 QImage::Format format;
849 qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual), &format, &needsRgbSwap);
851 if (format != QImage::Format_Invalid)
853 return QImage::Format_RGB32;
856int QXcbScreen::forcedDpi()
const
858 const int forcedDpi = m_virtualDesktop->forcedDpi();
864QDpi QXcbScreen::logicalDpi()
const
866 const int forcedDpi =
this->forcedDpi();
868 return QDpi(forcedDpi, forcedDpi);
878QPlatformCursor *QXcbScreen::cursor()
const
880 return m_cursor.get();
883void QXcbScreen::setOutput(xcb_randr_output_t outputId,
884 xcb_randr_get_output_info_reply_t *outputInfo)
888 m_crtc = outputInfo ? outputInfo->crtc : XCB_NONE;
890 m_outputName = getOutputName(outputInfo);
894void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
896 if (!connection()->isAtLeastXRandR12())
902 updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
905void QXcbScreen::updateGeometry(
const QRect &geometry, uint8_t rotation)
907 const Qt::ScreenOrientation oldOrientation = m_orientation;
910 case XCB_RANDR_ROTATION_ROTATE_0:
911 m_orientation = Qt::LandscapeOrientation;
913 m_sizeMillimeters = m_outputSizeMillimeters;
915 case XCB_RANDR_ROTATION_ROTATE_90:
916 m_orientation = Qt::PortraitOrientation;
918 m_sizeMillimeters = m_outputSizeMillimeters.transposed();
920 case XCB_RANDR_ROTATION_ROTATE_180:
921 m_orientation = Qt::InvertedLandscapeOrientation;
923 m_sizeMillimeters = m_outputSizeMillimeters;
925 case XCB_RANDR_ROTATION_ROTATE_270:
926 m_orientation = Qt::InvertedPortraitOrientation;
928 m_sizeMillimeters = m_outputSizeMillimeters.transposed();
935 if (m_sizeMillimeters.isEmpty())
936 m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi());
938 m_geometry = geometry;
939 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
940 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
941 if (m_orientation != oldOrientation)
942 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation);
945void QXcbScreen::updateAvailableGeometry()
947 QRect availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
948 if (m_availableGeometry != availableGeometry) {
949 m_availableGeometry = availableGeometry;
950 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
954void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
956 if (!connection()->isAtLeastXRandR12())
965 xcb_connection(), screen()->root);
967 xcb_randr_mode_info_iterator_t modesIter =
968 xcb_randr_get_screen_resources_current_modes_iterator(resources.get());
969 for (; modesIter.rem; xcb_randr_mode_info_next(&modesIter)) {
970 xcb_randr_mode_info_t *modeInfo = modesIter.data;
971 if (modeInfo->id == mode) {
972 const uint32_t dotCount = modeInfo->htotal * modeInfo->vtotal;
973 m_refreshRate = (dotCount != 0) ? modeInfo->dot_clock / qreal(dotCount) : 0;
979 QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), m_refreshRate);
983static inline bool translate(xcb_connection_t *connection, xcb_window_t child, xcb_window_t parent,
987 connection, child, parent, *x, *y);
988 if (!translate_reply)
990 *x = translate_reply->dst_x;
991 *y = translate_reply->dst_y;
995QPixmap QXcbScreen::grabWindow(WId window,
int xIn,
int yIn,
int width,
int height)
const
997 if (width == 0 || height == 0)
1002 QXcbScreen *screen =
const_cast<QXcbScreen *>(
this);
1003 xcb_window_t root = screen->root();
1009 const quint8 rootDepth = rootReply->depth;
1012 quint8 effectiveDepth = 0;
1017 windowSize = QSize(windowReply->width, windowReply->height);
1018 effectiveDepth = windowReply->depth;
1019 if (effectiveDepth == rootDepth) {
1025 if (!translate(xcb_connection(), window, root, &x, &y))
1032 effectiveDepth = rootDepth;
1033 windowSize = m_geometry.size();
1034 x += m_geometry.x();
1035 y += m_geometry.y();
1039 width = windowSize.width() - xIn;
1041 height = windowSize.height() - yIn;
1045 if (!attributes_reply)
1048 const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
1050 xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
1051 xcb_create_pixmap(xcb_connection(), effectiveDepth, pixmap, window, width, height);
1053 uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE;
1054 uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
1056 xcb_gcontext_t gc = xcb_generate_id(xcb_connection());
1057 xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list);
1059 xcb_copy_area(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height);
1061 QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, effectiveDepth, visual);
1062 xcb_free_gc(xcb_connection(), gc);
1063 xcb_free_pixmap(xcb_connection(), pixmap);
1068QXcbXSettings *QXcbScreen::xSettings()
const
1070 return m_virtualDesktop->xSettings();
1073QByteArray QXcbScreen::getOutputProperty(xcb_atom_t atom)
const
1077 auto reply =
Q_XCB_REPLY(xcb_randr_get_output_property, xcb_connection(),
1078 m_output, atom, XCB_ATOM_ANY, 0, 100,
false,
false);
1079 if (reply && reply->type == XCB_ATOM_INTEGER && reply->format == 8) {
1080 quint8 *data =
new quint8[reply->num_items];
1081 memcpy(data, xcb_randr_get_output_property_data(reply.get()), reply->num_items);
1082 result = QByteArray(
reinterpret_cast<
const char *>(data), reply->num_items);
1089QByteArray QXcbScreen::getEdid()
const
1092 if (!connection()->isAtLeastXRandR12())
1096 result = getOutputProperty(atom(QXcbAtom::AtomEDID));
1097 if (result.isEmpty())
1098 result = getOutputProperty(atom(QXcbAtom::AtomEDID_DATA));
1099 if (result.isEmpty())
1100 result = getOutputProperty(atom(QXcbAtom::AtomXFree86_DDC_EDID1_RAWDATA));
1107 debug << r.width() <<
'x' << r.height()
1108 << Qt::forcesign << r.x() << r.y() << Qt::noforcesign;
1113 debug << s.width() <<
'x' << s.height() <<
"mm";
1116QDebug operator<<(QDebug debug,
const QXcbScreen *screen)
1118 const QDebugStateSaver saver(debug);
1120 debug <<
"QXcbScreen(" << (
const void *)screen;
1122 debug << Qt::fixed << qSetRealNumberPrecision(1);
1123 debug <<
", name=" << screen->name();
1124 debug <<
", geometry=";
1125 formatRect(debug, screen->geometry());
1126 debug <<
", availableGeometry=";
1127 formatRect(debug, screen->availableGeometry());
1128 debug <<
", devicePixelRatio=" << screen->devicePixelRatio();
1129 debug <<
", logicalDpi=" << screen->logicalDpi();
1130 debug <<
", physicalSize=";
1131 formatSizeF(debug, screen->physicalSize());
1133 debug <<
", screenNumber=" << screen->screenNumber();
1134 const QSize virtualSize = screen->virtualDesktop()->size();
1135 debug <<
", virtualSize=" << virtualSize.width() <<
'x' << virtualSize.height() <<
" (";
1136 formatSizeF(debug, virtualSize);
1137 debug <<
"), orientation=" << screen->orientation();
1138 debug <<
", depth=" << screen->depth();
1139 debug <<
", refreshRate=" << screen->refreshRate();
1140 debug <<
", root=" << Qt::hex << screen->root();
1141 debug <<
", windowManagerName=" << screen->windowManagerName();
QXcbConnection * connection() const
xcb_connection_t * xcb_connection() const
xcb_colormap_t colormapForVisual(xcb_visualid_t) const
bool compositingActive() const
void addScreen(QPlatformScreen *s)
const xcb_visualtype_t * visualForId(xcb_visualid_t) const
void handleScreenChange(xcb_randr_screen_change_notify_event_t *change_event)
handle the XCB screen change event and update properties
const xcb_visualtype_t * visualForFormat(const QSurfaceFormat &format) const
quint8 depthOfVisual(xcb_visualid_t) const
QXcbXSettings * xSettings() const
void subscribeToXFixesSelectionNotify()
void setPrimaryScreen(QPlatformScreen *s)
QRect availableGeometry(const QRect &screenGeometry) const
void handleXFixesSelectionNotify(xcb_xfixes_selection_notify_event_t *notify_event)
QXcbScreen * screenAt(const QPoint &pos) const
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &format) const
xcb_screen_t * screen() const
#define Q_XCB_REPLY(call,...)
#define Q_XCB_REPLY_UNCHECKED(call,...)
static QSizeF sizeInMillimeters(const QSize &size, const QDpi &dpi)
static bool parseXftInt(const QByteArray &stringValue, int *value)
static void formatSizeF(QDebug &debug, const QSizeF s)
static QFontEngine::SubpixelAntialiasingType parseXftRgba(const QByteArray &stringValue)
static bool parseXftDpi(const QByteArray &stringValue, int *value)
static void formatRect(QDebug &debug, const QRect r)
static QFontEngine::HintStyle parseXftHintStyle(const QByteArray &stringValue)
static bool translate(xcb_connection_t *connection, xcb_window_t child, xcb_window_t parent, int *x, int *y)