15#include <QtAlgorithms>
17#include <qpa/qwindowsysteminterface.h>
18#include <private/qmath_p.h>
19#include <QtGui/private/qhighdpiscaling_p.h>
23QXcbVirtualDesktop::QXcbVirtualDesktop(QXcbConnection *connection, xcb_screen_t *screen,
int number)
24 : QXcbObject(connection)
27 , m_xSettings(
new QXcbXSettings(
this))
29 const QByteArray cmAtomName =
"_NET_WM_CM_S" + QByteArray::number(m_number);
30 m_net_wm_cm_atom = connection->internAtom(cmAtomName.constData());
31 m_compositingActive = connection->selectionOwner(m_net_wm_cm_atom);
33 m_workArea = getWorkArea();
39 const quint32 existingEventMask = !rootAttribs ? 0 : rootAttribs->your_event_mask;
41 const quint32 mask = XCB_CW_EVENT_MASK;
42 const quint32 values[] = {
44 XCB_EVENT_MASK_ENTER_WINDOW
45 | XCB_EVENT_MASK_LEAVE_WINDOW
46 | XCB_EVENT_MASK_PROPERTY_CHANGE
47 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
51 xcb_change_window_attributes(xcb_connection(), screen->root, mask, values);
55 atom(QXcbAtom::Atom_NET_SUPPORTING_WM_CHECK),
56 XCB_ATOM_WINDOW, 0, 1024);
57 if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
58 xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply.get()));
60 if (windowManager != XCB_WINDOW_NONE)
61 m_windowManagerName = QXcbWindow::windowTitle(connection, windowManager);
64 xcb_depth_iterator_t depth_iterator =
65 xcb_screen_allowed_depths_iterator(screen);
67 while (depth_iterator.rem) {
68 xcb_depth_t *depth = depth_iterator.data;
69 xcb_visualtype_iterator_t visualtype_iterator =
70 xcb_depth_visuals_iterator(depth);
72 while (visualtype_iterator.rem) {
73 xcb_visualtype_t *visualtype = visualtype_iterator.data;
74 m_visuals.insert(visualtype->visual_id, *visualtype);
75 m_visualDepths.insert(visualtype->visual_id, depth->depth);
76 xcb_visualtype_next(&visualtype_iterator);
79 xcb_depth_next(&depth_iterator);
82 auto dpiChangedCallback = [](QXcbVirtualDesktop *desktop,
const QByteArray &,
const QVariant &property,
void *) {
83 if (!desktop->setDpiFromXSettings(property))
85 const auto dpi = desktop->forcedDpi();
86 for (QXcbScreen *screen : desktop->connection()->screens())
87 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->QPlatformScreen::screen(), dpi, dpi);
89 setDpiFromXSettings(xSettings()->setting(
"Xft/DPI"));
90 xSettings()->registerCallbackForProperty(
"Xft/DPI", dpiChangedCallback,
nullptr);
97 for (
auto cmap : std::as_const(m_visualColormaps))
98 xcb_free_colormap(xcb_connection(), cmap);
103 const QSize virtualSize = size();
104 const QSize virtualSizeMillimeters = physicalSize();
106 return QDpi(Q_MM_PER_INCH * virtualSize.width() / virtualSizeMillimeters.width(),
107 Q_MM_PER_INCH * virtualSize.height() / virtualSizeMillimeters.height());
113 for (QXcbScreen *screen : screens) {
114 if (screen->virtualDesktop() ==
this && screen->geometry().contains(pos))
122 ((QXcbScreen *) s)->isPrimary() ? m_screens.prepend(s) : m_screens.append(s);
127 const int idx = m_screens.indexOf(s);
129 m_screens.swapItemsAt(0, idx);
140 return m_compositingActive;
142 return connection()->selectionOwner(m_net_wm_cm_atom);
147 if (notify_event->selection == m_net_wm_cm_atom)
148 m_compositingActive = notify_event->owner;
154 const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
155 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
156 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
157 xcb_xfixes_select_selection_input_checked(
xcb_connection(),
connection()->qtSelectionOwner(), m_net_wm_cm_atom, mask);
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
188 if (change_event->rotation == m_rotation)
191 m_rotation = change_event->rotation;
192 switch (m_rotation) {
193 case XCB_RANDR_ROTATION_ROTATE_0:
194 m_screen->width_in_pixels = change_event->width;
195 m_screen->height_in_pixels = change_event->height;
196 m_screen->width_in_millimeters = change_event->mwidth;
197 m_screen->height_in_millimeters = change_event->mheight;
199 case XCB_RANDR_ROTATION_ROTATE_90:
200 m_screen->width_in_pixels = change_event->height;
201 m_screen->height_in_pixels = change_event->width;
202 m_screen->width_in_millimeters = change_event->mheight;
203 m_screen->height_in_millimeters = change_event->mwidth;
205 case XCB_RANDR_ROTATION_ROTATE_180:
206 m_screen->width_in_pixels = change_event->width;
207 m_screen->height_in_pixels = change_event->height;
208 m_screen->width_in_millimeters = change_event->mwidth;
209 m_screen->height_in_millimeters = change_event->mheight;
211 case XCB_RANDR_ROTATION_ROTATE_270:
212 m_screen->width_in_pixels = change_event->height;
213 m_screen->height_in_pixels = change_event->width;
214 m_screen->width_in_millimeters = change_event->mheight;
215 m_screen->height_in_millimeters = change_event->mwidth;
219 case XCB_RANDR_ROTATION_REFLECT_X:
break;
220 case XCB_RANDR_ROTATION_REFLECT_Y:
break;
223 for (QPlatformScreen *platformScreen : std::as_const(m_screens)) {
224 QDpi ldpi = platformScreen->logicalDpi();
225 QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(platformScreen->screen(), ldpi.first, ldpi.second);
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
250 atom(QXcbAtom::Atom_NET_WORKAREA),
251 XCB_ATOM_CARDINAL, 0, 1024);
252 if (workArea && workArea->type == XCB_ATOM_CARDINAL && workArea->format == 32 && workArea->value_len >= 4) {
259 uint32_t *geom = (uint32_t*)xcb_get_property_value(workArea.get());
260 r = QRect(geom[0], geom[1], geom[2], geom[3]);
269 QRect workArea = getWorkArea();
270 if (m_workArea != workArea) {
271 m_workArea = workArea;
272 for (QPlatformScreen *screen : std::as_const(m_screens))
273 ((QXcbScreen *)screen)->updateAvailableGeometry();
279 return m_workArea.width() >= 0 ? screenGeometry & m_workArea : screenGeometry;
284 return QSizeF(Q_MM_PER_INCH * size.width() / dpi.first,
285 Q_MM_PER_INCH * size.height() / dpi.second);
289 const QByteArray &expectedIdentifier,
290 QByteArray& stringValue)
292 if (identifier.startsWith(expectedIdentifier)) {
293 stringValue = identifier.mid(expectedIdentifier.size());
303 *value = stringValue.toInt(&ok);
310 bool ok = parseXftInt(stringValue, value);
313 *value = qRound(stringValue.toDouble(&ok));
319 if (stringValue ==
"hintfull")
320 return QFontEngine::HintFull;
321 else if (stringValue ==
"hintnone")
322 return QFontEngine::HintNone;
323 else if (stringValue ==
"hintmedium")
324 return QFontEngine::HintMedium;
325 else if (stringValue ==
"hintslight")
326 return QFontEngine::HintLight;
328 return QFontEngine::HintStyle(-1);
333 if (stringValue ==
"none")
334 return QFontEngine::Subpixel_None;
335 else if (stringValue ==
"rgb")
336 return QFontEngine::Subpixel_RGB;
337 else if (stringValue ==
"bgr")
338 return QFontEngine::Subpixel_BGR;
339 else if (stringValue ==
"vrgb")
340 return QFontEngine::Subpixel_VRGB;
341 else if (stringValue ==
"vbgr")
342 return QFontEngine::Subpixel_VBGR;
344 return QFontEngine::SubpixelAntialiasingType(-1);
350 QByteArray resources;
353 false, screen()->root,
354 XCB_ATOM_RESOURCE_MANAGER,
355 XCB_ATOM_STRING, offset/4, 8192);
357 if (reply && reply->format == 8 && reply->type == XCB_ATOM_STRING) {
358 resources += QByteArray((
const char *)xcb_get_property_value(reply.get()), xcb_get_property_value_length(reply.get()));
359 offset += xcb_get_property_value_length(reply.get());
360 more = reply->bytes_after != 0;
367 QList<QByteArray> split = resources.split(
'\n');
368 for (
int i = 0; i < split.size(); ++i) {
369 const QByteArray &r = split.at(i);
371 QByteArray stringValue;
372 if (xResource(r,
"Xft.dpi:\t", stringValue)) {
373 if (parseXftDpi(stringValue, &value))
375 }
else if (xResource(r,
"Xft.hintstyle:\t", stringValue)) {
376 m_hintStyle = parseXftHintStyle(stringValue);
377 }
else if (xResource(r,
"Xft.antialias:\t", stringValue)) {
378 if (parseXftInt(stringValue, &value))
379 m_antialiasingEnabled = value;
380 }
else if (xResource(r,
"Xft.rgba:\t", stringValue)) {
381 m_subpixelType = parseXftRgba(stringValue);
389 int dpiTimes1k = property.toInt(&ok);
392 int dpi = dpiTimes1k / 1024;
393 if (m_forcedDpi == dpi)
401 const xcb_visualid_t xcb_visualid =
connection()->hasDefaultVisualId() ?
connection()->defaultVisualId()
403 const xcb_visualtype_t *xcb_visualtype =
visualForId(xcb_visualid
);
405 const int redSize = qPopulationCount(xcb_visualtype->red_mask);
406 const int greenSize = qPopulationCount(xcb_visualtype->green_mask);
407 const int blueSize = qPopulationCount(xcb_visualtype->blue_mask);
409 QSurfaceFormat result = format;
411 if (result.redBufferSize() < 0)
412 result.setRedBufferSize(redSize);
414 if (result.greenBufferSize() < 0)
415 result.setGreenBufferSize(greenSize);
417 if (result.blueBufferSize() < 0)
418 result.setBlueBufferSize(blueSize);
425 const xcb_visualtype_t *candidate =
nullptr;
427 for (
const xcb_visualtype_t &xcb_visualtype : m_visuals) {
429 const int redSize = qPopulationCount(xcb_visualtype.red_mask);
430 const int greenSize = qPopulationCount(xcb_visualtype.green_mask);
431 const int blueSize = qPopulationCount(xcb_visualtype.blue_mask);
432 const int alphaSize = depthOfVisual(xcb_visualtype.visual_id) - redSize - greenSize - blueSize;
434 if (format.redBufferSize() != -1 && redSize != format.redBufferSize())
437 if (format.greenBufferSize() != -1 && greenSize != format.greenBufferSize())
440 if (format.blueBufferSize() != -1 && blueSize != format.blueBufferSize())
443 if (format.alphaBufferSize() != -1 && alphaSize != format.alphaBufferSize())
447 if (qCountTrailingZeroBits(xcb_visualtype.blue_mask) == 0)
448 return &xcb_visualtype;
453 candidate = &xcb_visualtype;
461 QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
462 if (it == m_visuals.constEnd())
469 QMap<xcb_visualid_t, quint8>::const_iterator it = m_visualDepths.find(visualid);
470 if (it == m_visualDepths.constEnd())
477 auto it = m_visualColormaps.constFind(visualid);
478 if (it != m_visualColormaps.constEnd())
483 XCB_COLORMAP_ALLOC_NONE,
487 m_visualColormaps.insert(visualid, cmap);
491QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
492 xcb_randr_output_t outputId, xcb_randr_get_output_info_reply_t *output)
493 : QXcbObject(connection)
494 , m_virtualDesktop(virtualDesktop)
497 , m_crtc(output ? output->crtc : XCB_NONE)
498 , m_outputName(getOutputName(output))
499 , m_outputSizeMillimeters(output ? QSize(output->mm_width, output->mm_height) : QSize())
500 , m_cursor(std::make_unique<QXcbCursor>(connection,
this))
502 if (connection->isAtLeastXRandR12()) {
504 m_crtc, output ? output->timestamp : 0);
506 updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
507 updateRefreshRate(crtc->mode);
511 if (m_geometry.isEmpty())
512 m_geometry = QRect(QPoint(), virtualDesktop->size());
514 if (m_availableGeometry.isEmpty())
515 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
517 if (m_sizeMillimeters.isEmpty())
518 m_sizeMillimeters = virtualDesktop->physicalSize();
520 updateColorSpaceAndEdid();
523void QXcbScreen::updateColorSpaceAndEdid()
528 false, screen()->root,
529 connection()->atom(QXcbAtom::Atom_ICC_PROFILE),
530 XCB_ATOM_CARDINAL, 0, 8192);
531 if (reply->format == 8 && reply->type == XCB_ATOM_CARDINAL) {
532 QByteArray data(
reinterpret_cast<
const char *>(xcb_get_property_value(reply.get())), reply->value_len);
533 m_colorSpace = QColorSpace::fromIccProfile(data);
536 if (connection()->isAtLeastXRandR12()) {
537 QByteArray edid = getEdid();
538 if (m_edid.parse(edid)) {
539 qCDebug(lcQpaScreen,
"EDID data for output \"%s\": identifier '%s', manufacturer '%s',"
540 "model '%s', serial '%s', physical size: %.2fx%.2f",
541 name().toLatin1().constData(),
542 m_edid.identifier.toLatin1().constData(),
543 m_edid.manufacturer.toLatin1().constData(),
544 m_edid.model.toLatin1().constData(),
545 m_edid.serialNumber.toLatin1().constData(),
546 m_edid.physicalSize.width(), m_edid.physicalSize.height());
547 if (!m_colorSpace.isValid()) {
549 m_colorSpace = QColorSpace::SRgb;
551 if (!m_edid.useTables) {
552 m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
553 m_edid.greenChromaticity, m_edid.blueChromaticity,
554 QColorSpace::TransferFunction::Gamma, m_edid.gamma);
556 if (m_edid.tables.size() == 1) {
557 m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
558 m_edid.greenChromaticity, m_edid.blueChromaticity,
560 }
else if (m_edid.tables.size() == 3) {
561 m_colorSpace = QColorSpace(m_edid.whiteChromaticity, m_edid.redChromaticity,
562 m_edid.greenChromaticity, m_edid.blueChromaticity,
563 m_edid.tables[0], m_edid.tables[1], m_edid.tables[2]);
571 qCDebug(lcQpaScreen) <<
"Failed to parse EDID data for output" << name() <<
572 "edid data: " << edid;
575 if (!m_colorSpace.isValid())
576 m_colorSpace = QColorSpace::SRgb;
579QXcbScreen::QXcbScreen(QXcbConnection *connection, QXcbVirtualDesktop *virtualDesktop,
580 xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
581 : QXcbObject(connection)
582 , m_virtualDesktop(virtualDesktop)
583 , m_monitor(monitorInfo)
584 , m_cursor(std::make_unique<QXcbCursor>(connection,
this))
586 setMonitor(monitorInfo, timestamp);
589void QXcbScreen::setMonitor(xcb_randr_monitor_info_t *monitorInfo, xcb_timestamp_t timestamp)
591 if (!connection()->isAtLeastXRandR15())
598 m_singlescreen =
false;
603 m_outputName = defaultName();
608 m_monitor = monitorInfo;
609 qCDebug(lcQpaScreen) <<
"xcb_randr_monitor_info_t: primary=" << m_monitor->primary <<
", x=" << m_monitor->x <<
", y=" << m_monitor->y
610 <<
", width=" << m_monitor->width <<
", height=" << m_monitor->height
611 <<
", width_in_millimeters=" << m_monitor->width_in_millimeters <<
", height_in_millimeters=" << m_monitor->height_in_millimeters;
612 QRect monitorGeometry = QRect(m_monitor->x, m_monitor->y,
613 m_monitor->width, m_monitor->height);
614 m_sizeMillimeters = QSize(m_monitor->width_in_millimeters, m_monitor->height_in_millimeters);
616 int outputCount = xcb_randr_monitor_info_outputs_length(m_monitor);
617 xcb_randr_output_t *outputs =
nullptr;
619 outputs = xcb_randr_monitor_info_outputs(m_monitor);
620 for (
int i = 0; i < outputCount; i++) {
622 xcb_connection(), outputs[i], timestamp);
627 if (output->connection != XCB_RANDR_CONNECTION_CONNECTED) {
628 qCDebug(lcQpaScreen,
"Output %s is not connected", qPrintable(
629 QString::fromUtf8((
const char*)xcb_randr_get_output_info_name(output.get()),
630 xcb_randr_get_output_info_name_length(output.get()))));
634 if (output->crtc == XCB_NONE) {
635 qCDebug(lcQpaScreen,
"Output %s is not enabled", qPrintable(
636 QString::fromUtf8((
const char*)xcb_randr_get_output_info_name(output.get()),
637 xcb_randr_get_output_info_name_length(output.get()))));
641 m_outputs << outputs[i];
642 if (m_output == XCB_NONE) {
643 m_output = outputs[i];
644 m_outputSizeMillimeters = QSize(output->mm_width, output->mm_height);
646 m_crtcs << output->crtc;
647 if (m_crtc == XCB_NONE)
648 m_crtc = output->crtc;
652 if (m_crtcs.size() == 1) {
654 xcb_connection(), m_crtcs[0], timestamp);
655 if (crtc == XCB_NONE) {
656 qCDebug(lcQpaScreen,
"Didn't get crtc info when m_crtcs.size() == 1");
658 m_singlescreen = (monitorGeometry == (QRect(crtc->x, crtc->y, crtc->width, crtc->height)));
659 if (m_singlescreen) {
661 updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
662 if (mode() != crtc->mode)
663 updateRefreshRate(crtc->mode);
670 m_geometry = monitorGeometry;
671 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
672 if (m_geometry.isEmpty())
673 m_geometry = QRect(QPoint(), virtualDesktop()->size());
674 if (m_availableGeometry.isEmpty())
675 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
677 if (m_sizeMillimeters.isEmpty())
678 m_sizeMillimeters = virtualDesktop()->physicalSize();
680 m_outputName = getName(monitorInfo);
682 if (connection()->primaryScreenNumber() == virtualDesktop()->number()) {
683 if (monitorInfo->primary || isPrimaryInXScreen())
687 updateColorSpaceAndEdid();
690QString QXcbScreen::defaultName()
693 QByteArray displayName = connection()->displayName();
694 int dotPos = displayName.lastIndexOf(
'.');
696 displayName.truncate(dotPos);
697 name = QString::fromLocal8Bit(displayName) + u'.'
698 + QString::number(m_virtualDesktop->number());
702bool QXcbScreen::isPrimaryInXScreen()
704 auto primary =
Q_XCB_REPLY(xcb_randr_get_output_primary, connection()->xcb_connection(), root());
706 qWarning(
"failed to get the primary output of the screen");
708 const bool isPrimary = primary ? (m_monitor ? m_outputs.contains(primary->output) : m_output == primary->output) :
false;
713QXcbScreen::~QXcbScreen()
717QString QXcbScreen::getOutputName(xcb_randr_get_output_info_reply_t *outputInfo)
721 name = QString::fromUtf8((
const char*)xcb_randr_get_output_info_name(outputInfo),
722 xcb_randr_get_output_info_name_length(outputInfo));
724 name = defaultName();
729QString QXcbScreen::getName(xcb_randr_monitor_info_t *monitorInfo)
732 QByteArray ba = connection()->atomName(monitorInfo->name);
734 name = QString::fromLatin1(ba.constData());
736 QByteArray displayName = connection()->displayName();
737 int dotPos = displayName.lastIndexOf(
'.');
739 displayName.truncate(dotPos);
740 name = QString::fromLocal8Bit(displayName) + u'.'
741 + QString::number(m_virtualDesktop->number());
746QString QXcbScreen::manufacturer()
const
748 return m_edid.manufacturer;
751QString QXcbScreen::model()
const
756QString QXcbScreen::serialNumber()
const
758 return m_edid.serialNumber;
761QWindow *QXcbScreen::topLevelAt(
const QPoint &p)
const
763 xcb_window_t root = screen()->root;
768 xcb_window_t parent = root;
769 xcb_window_t child = root;
772 auto translate_reply =
Q_XCB_REPLY_UNCHECKED(xcb_translate_coordinates, xcb_connection(), parent, child, x, y);
773 if (!translate_reply) {
778 child = translate_reply->child;
779 x = translate_reply->dst_x;
780 y = translate_reply->dst_y;
782 if (!child || child == root)
785 QPlatformWindow *platformWindow = connection()->platformWindowFromId(child);
787 return platformWindow->window();
788 }
while (parent != child);
793void QXcbScreen::windowShown(QXcbWindow *window)
796 if (!connection()->startupId().isEmpty() && window->window()->isTopLevel()) {
797 sendStartupMessage(QByteArrayLiteral(
"remove: ID=") + connection()->startupId());
798 connection()->setStartupId({});
802QSurfaceFormat QXcbScreen::surfaceFormatFor(
const QSurfaceFormat &format)
const
804 return m_virtualDesktop->surfaceFormatFor(format);
807const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid)
const
809 return m_virtualDesktop->visualForId(visualid);
812void QXcbScreen::sendStartupMessage(
const QByteArray &message)
const
814 xcb_window_t rootWindow = root();
816 xcb_client_message_event_t ev;
817 ev.response_type = XCB_CLIENT_MESSAGE;
819 ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO_BEGIN);
821 ev.window = rootWindow;
823 int length = message.size() + 1;
824 const char *data = message.constData();
827 ev.type = connection()->atom(QXcbAtom::Atom_NET_STARTUP_INFO);
829 const int start = sent;
830 const int numBytes = qMin(length - start, 20);
831 memcpy(ev.data.data8, data + start, numBytes);
832 xcb_send_event(connection()->xcb_connection(),
false, rootWindow, XCB_EVENT_MASK_PROPERTY_CHANGE, (
const char *) &ev);
835 }
while (sent < length);
838QRect QXcbScreen::availableGeometry()
const
840 static bool enforceNetWorkarea = !qEnvironmentVariableIsEmpty(
"QT_RELY_ON_NET_WORKAREA_ATOM");
841 bool isMultiHeadSystem = virtualSiblings().size() > 1;
842 bool useScreenGeometry = isMultiHeadSystem && !enforceNetWorkarea;
843 return useScreenGeometry ? m_geometry : m_availableGeometry;
846QImage::Format QXcbScreen::format()
const
848 QImage::Format format;
850 qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual), &format, &needsRgbSwap);
852 if (format != QImage::Format_Invalid)
854 return QImage::Format_RGB32;
857int QXcbScreen::forcedDpi()
const
859 const int forcedDpi = m_virtualDesktop->forcedDpi();
865QDpi QXcbScreen::logicalDpi()
const
867 const int forcedDpi =
this->forcedDpi();
869 return QDpi(forcedDpi, forcedDpi);
879QPlatformCursor *QXcbScreen::cursor()
const
881 return m_cursor.get();
884void QXcbScreen::setOutput(xcb_randr_output_t outputId,
885 xcb_randr_get_output_info_reply_t *outputInfo)
889 m_crtc = outputInfo ? outputInfo->crtc : XCB_NONE;
891 m_outputName = getOutputName(outputInfo);
895void QXcbScreen::updateGeometry(xcb_timestamp_t timestamp)
897 if (!connection()->isAtLeastXRandR12())
903 updateGeometry(QRect(crtc->x, crtc->y, crtc->width, crtc->height), crtc->rotation);
906void QXcbScreen::updateGeometry(
const QRect &geometry, uint8_t rotation)
908 const Qt::ScreenOrientation oldOrientation = m_orientation;
911 case XCB_RANDR_ROTATION_ROTATE_0:
912 m_orientation = Qt::LandscapeOrientation;
914 m_sizeMillimeters = m_outputSizeMillimeters;
916 case XCB_RANDR_ROTATION_ROTATE_90:
917 m_orientation = Qt::PortraitOrientation;
919 m_sizeMillimeters = m_outputSizeMillimeters.transposed();
921 case XCB_RANDR_ROTATION_ROTATE_180:
922 m_orientation = Qt::InvertedLandscapeOrientation;
924 m_sizeMillimeters = m_outputSizeMillimeters;
926 case XCB_RANDR_ROTATION_ROTATE_270:
927 m_orientation = Qt::InvertedPortraitOrientation;
929 m_sizeMillimeters = m_outputSizeMillimeters.transposed();
936 if (m_sizeMillimeters.isEmpty())
937 m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi());
939 m_geometry = geometry;
940 m_availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
941 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
942 if (m_orientation != oldOrientation)
943 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), m_orientation);
946void QXcbScreen::updateAvailableGeometry()
948 QRect availableGeometry = m_virtualDesktop->availableGeometry(m_geometry);
949 if (m_availableGeometry != availableGeometry) {
950 m_availableGeometry = availableGeometry;
951 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), m_geometry, m_availableGeometry);
955void QXcbScreen::updateRefreshRate(xcb_randr_mode_t mode)
957 if (!connection()->isAtLeastXRandR12())
966 xcb_connection(), screen()->root);
968 xcb_randr_mode_info_iterator_t modesIter =
969 xcb_randr_get_screen_resources_current_modes_iterator(resources.get());
970 for (; modesIter.rem; xcb_randr_mode_info_next(&modesIter)) {
971 xcb_randr_mode_info_t *modeInfo = modesIter.data;
972 if (modeInfo->id == mode) {
973 const uint32_t dotCount = modeInfo->htotal * modeInfo->vtotal;
974 m_refreshRate = (dotCount != 0) ? modeInfo->dot_clock / qreal(dotCount) : 0;
980 QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), m_refreshRate);
984static inline bool translate(xcb_connection_t *connection, xcb_window_t child, xcb_window_t parent,
988 connection, child, parent, *x, *y);
989 if (!translate_reply)
991 *x = translate_reply->dst_x;
992 *y = translate_reply->dst_y;
996QPixmap QXcbScreen::grabWindow(WId window,
int xIn,
int yIn,
int width,
int height)
const
998 if (width == 0 || height == 0)
1003 QXcbScreen *screen =
const_cast<QXcbScreen *>(
this);
1004 xcb_window_t root = screen->root();
1010 const quint8 rootDepth = rootReply->depth;
1013 quint8 effectiveDepth = 0;
1018 windowSize = QSize(windowReply->width, windowReply->height);
1019 effectiveDepth = windowReply->depth;
1020 if (effectiveDepth == rootDepth) {
1026 if (!translate(xcb_connection(), window, root, &x, &y))
1033 effectiveDepth = rootDepth;
1034 windowSize = m_geometry.size();
1035 x += m_geometry.x();
1036 y += m_geometry.y();
1040 width = windowSize.width() - xIn;
1042 height = windowSize.height() - yIn;
1046 if (!attributes_reply)
1049 const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
1051 xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
1052 xcb_create_pixmap(xcb_connection(), effectiveDepth, pixmap, window, width, height);
1054 uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE;
1055 uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
1057 xcb_gcontext_t gc = xcb_generate_id(xcb_connection());
1058 xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list);
1060 xcb_copy_area(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height);
1062 QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, effectiveDepth, visual);
1063 xcb_free_gc(xcb_connection(), gc);
1064 xcb_free_pixmap(xcb_connection(), pixmap);
1069QXcbXSettings *QXcbScreen::xSettings()
const
1071 return m_virtualDesktop->xSettings();
1074QByteArray QXcbScreen::getOutputProperty(xcb_atom_t atom)
const
1078 auto reply =
Q_XCB_REPLY(xcb_randr_get_output_property, xcb_connection(),
1079 m_output, atom, XCB_ATOM_ANY, 0, 100,
false,
false);
1080 if (reply && reply->type == XCB_ATOM_INTEGER && reply->format == 8) {
1081 quint8 *data =
new quint8[reply->num_items];
1082 memcpy(data, xcb_randr_get_output_property_data(reply.get()), reply->num_items);
1083 result = QByteArray(
reinterpret_cast<
const char *>(data), reply->num_items);
1090QByteArray QXcbScreen::getEdid()
const
1093 if (!connection()->isAtLeastXRandR12())
1097 result = getOutputProperty(atom(QXcbAtom::AtomEDID));
1098 if (result.isEmpty())
1099 result = getOutputProperty(atom(QXcbAtom::AtomEDID_DATA));
1100 if (result.isEmpty())
1101 result = getOutputProperty(atom(QXcbAtom::AtomXFree86_DDC_EDID1_RAWDATA));
1108 debug << r.width() <<
'x' << r.height()
1109 << Qt::forcesign << r.x() << r.y() << Qt::noforcesign;
1114 debug << s.width() <<
'x' << s.height() <<
"mm";
1117QDebug operator<<(QDebug debug,
const QXcbScreen *screen)
1119 const QDebugStateSaver saver(debug);
1121 debug <<
"QXcbScreen(" << (
const void *)screen;
1123 debug << Qt::fixed << qSetRealNumberPrecision(1);
1124 debug <<
", name=" << screen->name();
1125 debug <<
", geometry=";
1126 formatRect(debug, screen->geometry());
1127 debug <<
", availableGeometry=";
1128 formatRect(debug, screen->availableGeometry());
1129 debug <<
", devicePixelRatio=" << screen->devicePixelRatio();
1130 debug <<
", logicalDpi=" << screen->logicalDpi();
1131 debug <<
", physicalSize=";
1132 formatSizeF(debug, screen->physicalSize());
1134 debug <<
", screenNumber=" << screen->screenNumber();
1135 const QSize virtualSize = screen->virtualDesktop()->size();
1136 debug <<
", virtualSize=" << virtualSize.width() <<
'x' << virtualSize.height() <<
" (";
1137 formatSizeF(debug, virtualSize);
1138 debug <<
"), orientation=" << screen->orientation();
1139 debug <<
", depth=" << screen->depth();
1140 debug <<
", refreshRate=" << screen->refreshRate();
1141 debug <<
", root=" << Qt::hex << screen->root();
1142 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)