229void QXcbWindow::create()
231 xcb_window_t old_m_window = m_window;
233 QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
234 QGuiApplication::sendEvent(window(), &e);
238 m_windowState = Qt::WindowNoState;
239 m_trayIconWindow = isTrayIconWindow(window());
241 Qt::WindowType type = window()->type();
243 QXcbScreen *currentScreen = xcbScreen();
244 QXcbScreen *platformScreen = QPlatformWindow::parent() ? parentScreen() : initialScreen();
245 QRect rect = QPlatformWindow::parent()
246 ? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen)
247 : QHighDpi::toNativePixels(window()->geometry(), platformScreen);
249 const QSize minimumSize = windowMinimumSize();
250 if (rect.width() > 0 || rect.height() > 0) {
251 rect.setWidth(qBound(1, rect.width(),
XCOORD_MAX));
252 rect.setHeight(qBound(1, rect.height(),
XCOORD_MAX));
253 }
else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
254 rect.setSize(minimumSize);
256 rect.setWidth(QHighDpi::toNativePixels(
int(defaultWindowWidth), platformScreen->QPlatformScreen::screen()));
257 rect.setHeight(QHighDpi::toNativePixels(
int(defaultWindowHeight), platformScreen->QPlatformScreen::screen()));
260 QPlatformWindow::setGeometry(rect);
262 if (platformScreen != currentScreen)
263 QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
265 xcb_window_t xcb_parent_id = platformScreen->root();
266 if (QPlatformWindow::parent()) {
267 xcb_parent_id =
static_cast<QXcbWindow *>(QPlatformWindow::parent())->xcb_window();
268 m_embedded = QPlatformWindow::parent()->isForeignWindow();
270 QSurfaceFormat parentFormat = QPlatformWindow::parent()->window()->requestedFormat();
271 if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) {
272 window()->setFormat(parentFormat);
276 resolveFormat(platformScreen->surfaceFormatFor(window()->requestedFormat()));
278 const xcb_visualtype_t *visual =
nullptr;
280 if (m_trayIconWindow && connection()->systemTrayTracker()) {
281 visual = platformScreen->visualForId(connection()->systemTrayTracker()->visualId());
282 }
else if (connection()->hasDefaultVisualId()) {
283 visual = platformScreen->visualForId(connection()->defaultVisualId());
285 qWarning() <<
"Failed to use requested visual id.";
288 if (QPlatformWindow::parent()) {
294 if (window()->surfaceType() == QSurface::VulkanSurface
295 && QPlatformWindow::parent()->window()->surfaceType() != QSurface::VulkanSurface)
297 visual = platformScreen->visualForId(
static_cast<QXcbWindow *>(QPlatformWindow::parent())->visualId());
302 visual = createVisual();
305 qWarning() <<
"Falling back to using screens root_visual.";
306 visual = platformScreen->visualForId(platformScreen->screen()->root_visual);
311 m_visualId = visual->visual_id;
312 m_depth = platformScreen->depthOfVisual(m_visualId);
313 setImageFormatForVisual(visual);
315 quint32 mask = XCB_CW_BACK_PIXMAP
316 | XCB_CW_BORDER_PIXEL
318 | XCB_CW_OVERRIDE_REDIRECT
324 XCB_BACK_PIXMAP_NONE,
325 platformScreen->screen()->black_pixel,
326 XCB_GRAVITY_NORTH_WEST,
327 type == Qt::Popup || type == Qt::ToolTip || (window()->flags() & Qt::BypassWindowManagerHint),
328 type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer,
330 platformScreen->colormapForVisual(m_visualId)
333 m_window = xcb_generate_id(xcb_connection());
334 xcb_create_window(xcb_connection(),
343 XCB_WINDOW_CLASS_INPUT_OUTPUT,
348 connection()->addWindowEventListener(m_window,
this);
350 propagateSizeHints();
352 xcb_atom_t properties[5];
353 int propertyCount = 0;
354 properties[propertyCount++] = atom(QXcbAtom::AtomWM_DELETE_WINDOW);
355 properties[propertyCount++] = atom(QXcbAtom::AtomWM_TAKE_FOCUS);
356 properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_PING);
358 if (connection()->hasXSync())
359 properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST);
361 if (window()->flags() & Qt::WindowContextHelpButtonHint)
362 properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP);
364 xcb_change_property(xcb_connection(),
365 XCB_PROP_MODE_REPLACE,
367 atom(QXcbAtom::AtomWM_PROTOCOLS),
375 const QByteArray wmClass = QXcbIntegration::instance()->wmClass();
376 if (!wmClass.isEmpty()) {
377 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
378 m_window, atom(QXcbAtom::AtomWM_CLASS),
379 XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData());
382 QString desktopFileName = QGuiApplication::desktopFileName();
383 if (QGuiApplication::desktopFileName().isEmpty()) {
384 QFileInfo fi = QFileInfo(QCoreApplication::instance()->applicationFilePath());
385 QStringList domainName =
386 QCoreApplication::instance()->organizationDomain().split(QLatin1Char(
'.'),
389 if (domainName.isEmpty()) {
390 desktopFileName = fi.baseName();
392 for (
int i = 0; i < domainName.size(); ++i)
393 desktopFileName.prepend(QLatin1Char(
'.')).prepend(domainName.at(i));
394 desktopFileName.append(fi.baseName());
397 if (!desktopFileName.isEmpty()) {
398 const QByteArray dfName = desktopFileName.toUtf8();
399 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
400 m_window, atom(QXcbAtom::Atom_KDE_NET_WM_DESKTOP_FILE),
401 atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
402 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
403 m_window, atom(QXcbAtom::Atom_GTK_APPLICATION_ID),
404 atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
407 if (connection()->hasXSync()) {
408 m_syncCounter = xcb_generate_id(xcb_connection());
409 xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue);
411 xcb_change_property(xcb_connection(),
412 XCB_PROP_MODE_REPLACE,
414 atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST_COUNTER),
422 quint32 pid = getpid();
423 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
424 atom(QXcbAtom::Atom_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
427 const QByteArray clientMachine = QSysInfo::machineHostName().toLocal8Bit();
428 if (!clientMachine.isEmpty()) {
429 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
430 atom(QXcbAtom::AtomWM_CLIENT_MACHINE), XCB_ATOM_STRING, 8,
431 clientMachine.size(), clientMachine.constData());
436 xcb_icccm_wm_hints_t hints;
437 memset(&hints, 0,
sizeof(hints));
438 hints.flags = XCB_ICCCM_WM_HINT_WINDOW_GROUP;
439 hints.window_group = connection()->clientLeader();
440 xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints);
442 xcb_window_t leader = connection()->clientLeader();
443 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
444 atom(QXcbAtom::AtomWM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
448 quint32 data[] = { XEMBED_VERSION, XEMBED_MAPPED };
449 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
450 atom(QXcbAtom::Atom_XEMBED_INFO),
451 atom(QXcbAtom::Atom_XEMBED_INFO),
452 32, 2, (
void *)data);
454 if (connection()->hasXInput2())
455 connection()->xi2SelectDeviceEvents(m_window);
457 setWindowState(window()->windowStates());
458 setWindowFlags(window()->flags());
459 setWindowTitle(window()->title());
462 connection()->sync();
464#if QT_CONFIG(draganddrop)
465 connection()->drag()->dndEnable(
this,
true);
468 const qreal opacity = qt_window_private(window())->opacity;
469 if (!qFuzzyCompare(opacity, qreal(1.0)))
472 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
474 if (window()->isTopLevel())
475 setWindowIcon(window()->icon());
477 if (window()->dynamicPropertyNames().contains(wm_window_role_property_id)) {
478 QByteArray wmWindowRole = window()->property(wm_window_role_property_id).toByteArray();
479 setWindowRole(QString::fromLatin1(wmWindowRole));
482 if (m_trayIconWindow)
483 m_embedded = requestSystemTrayWindowDock();
485 if (m_window != old_m_window) {
486 if (!m_wmTransientForChildren.isEmpty()) {
487 QList<QPointer<QXcbWindow>> transientChildren = m_wmTransientForChildren;
488 m_wmTransientForChildren.clear();
489 for (
auto transientChild : transientChildren) {
491 transientChild->updateWmTransientFor();
609QMargins QXcbWindow::frameMargins()
const
611 if (m_dirtyFrameMargins) {
612 if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_FRAME_EXTENTS))) {
613 auto reply =
Q_XCB_REPLY(xcb_get_property, xcb_connection(),
false, m_window,
614 atom(QXcbAtom::Atom_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
615 if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) {
616 quint32 *data = (quint32 *)xcb_get_property_value(reply.get());
618 m_frameMargins = QMargins(data[0], data[2], data[1], data[3]);
619 m_dirtyFrameMargins =
false;
620 return m_frameMargins;
626 xcb_window_t window = m_window;
627 xcb_window_t parent = m_window;
629 bool foundRoot =
false;
631 const QList<xcb_window_t> &virtualRoots =
632 connection()->wmSupport()->virtualRoots();
637 if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1 || reply->parent == XCB_WINDOW_NONE) {
641 parent = reply->parent;
644 m_dirtyFrameMargins =
false;
645 m_frameMargins = QMargins();
646 return m_frameMargins;
652 auto reply =
Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), window, parent, 0, 0);
654 offset = QPoint(reply->dst_x, reply->dst_y);
657 auto geom =
Q_XCB_REPLY(xcb_get_geometry, xcb_connection(), parent);
668 int left = offset.x() + geom->border_width;
669 int top = offset.y() + geom->border_width;
670 int right = geom->width + geom->border_width - geometry().width() - offset.x();
671 int bottom = geom->height + geom->border_width - geometry().height() - offset.y();
673 m_frameMargins = QMargins(left, top, right, bottom);
676 m_dirtyFrameMargins =
false;
679 return m_frameMargins;
893QXcbWindow::NetWmStates QXcbWindow::netWmStates()
898 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
899 XCB_ATOM_ATOM, 0, 1024);
901 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
902 const xcb_atom_t *states =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
903 const xcb_atom_t *statesEnd = states + reply->length;
904 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
905 result |= NetWmStateAbove;
906 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
907 result |= NetWmStateBelow;
908 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
909 result |= NetWmStateFullScreen;
910 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
911 result |= NetWmStateMaximizedHorz;
912 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
913 result |= NetWmStateMaximizedVert;
914 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
915 result |= NetWmStateModal;
916 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
917 result |= NetWmStateStaysOnTop;
918 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
919 result |= NetWmStateDemandsAttention;
920 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
921 result |= NetWmStateHidden;
923 qCDebug(lcQpaXcb,
"getting net wm state (%x), empty\n", m_window);
968void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
970 Qt::WindowType type =
static_cast<Qt::WindowType>(
int(flags & Qt::WindowType_Mask));
972 QtMotifWmHints mwmhints;
973 memset(&mwmhints, 0,
sizeof(mwmhints));
975 if (type != Qt::SplashScreen) {
976 mwmhints.flags |= MWM_HINTS_DECORATIONS;
978 bool customize = flags & Qt::CustomizeWindowHint;
979 if (type == Qt::Window && !customize) {
980 const Qt::WindowFlags defaultFlags = Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
981 if (!(flags & defaultFlags))
982 flags |= defaultFlags;
984 if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
985 mwmhints.decorations |= MWM_DECOR_BORDER;
986 mwmhints.decorations |= MWM_DECOR_RESIZEH;
987 mwmhints.decorations |= MWM_DECOR_TITLE;
989 if (flags & Qt::WindowSystemMenuHint)
990 mwmhints.decorations |= MWM_DECOR_MENU;
992 if (flags & Qt::WindowMinimizeButtonHint) {
993 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
994 mwmhints.functions |= MWM_FUNC_MINIMIZE;
997 if (flags & Qt::WindowMaximizeButtonHint) {
998 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
999 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
1002 if (flags & Qt::WindowCloseButtonHint)
1003 mwmhints.functions |= MWM_FUNC_CLOSE;
1007 mwmhints.decorations = MWM_DECOR_ALL;
1010 if (mwmhints.functions != 0) {
1011 mwmhints.flags |= MWM_HINTS_FUNCTIONS;
1012 mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
1014 mwmhints.functions = MWM_FUNC_ALL;
1017 if (!(flags & Qt::FramelessWindowHint)
1018 && flags & Qt::CustomizeWindowHint
1019 && flags & Qt::WindowTitleHint
1021 (Qt::WindowMinimizeButtonHint
1022 | Qt::WindowMaximizeButtonHint
1023 | Qt::WindowCloseButtonHint)))
1026 mwmhints.flags = MWM_HINTS_FUNCTIONS;
1027 mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
1028 mwmhints.decorations = 0;
1031 if (mwmhints.flags) {
1032 xcb_change_property(xcb_connection(),
1033 XCB_PROP_MODE_REPLACE,
1035 atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
1036 atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
1041 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_MOTIF_WM_HINTS));
1085void QXcbWindow::setNetWmStateOnUnmappedWindow()
1087 QMutexLocker locker(&m_mappedMutex);
1088 if (Q_UNLIKELY(m_mapped))
1089 qCDebug(lcQpaXcb()) <<
"internal info: " << Q_FUNC_INFO <<
"called on mapped window";
1092 const Qt::WindowFlags flags = window()->flags();
1093 if (flags & Qt::WindowStaysOnTopHint) {
1094 states |= NetWmStateAbove;
1095 states |= NetWmStateStaysOnTop;
1096 }
else if (flags & Qt::WindowStaysOnBottomHint) {
1097 states |= NetWmStateBelow;
1100 if (window()->windowStates() & Qt::WindowMinimized)
1101 states |= NetWmStateHidden;
1103 if (window()->windowStates() & Qt::WindowFullScreen)
1104 states |= NetWmStateFullScreen;
1106 if (window()->windowStates() & Qt::WindowMaximized) {
1107 states |= NetWmStateMaximizedHorz;
1108 states |= NetWmStateMaximizedVert;
1111 if (window()->modality() != Qt::NonModal)
1112 states |= NetWmStateModal;
1122 QList<xcb_atom_t> atoms;
1124 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
1125 XCB_ATOM_ATOM, 0, 1024);
1126 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) {
1127 const xcb_atom_t *data =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
1128 atoms.resize(reply->value_len);
1129 memcpy((
void *)&atoms.first(), (
void *)data, reply->value_len *
sizeof(xcb_atom_t));
1132 if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
1133 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE));
1134 if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
1135 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW));
1136 if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
1137 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN));
1138 if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
1139 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
1140 if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
1141 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ));
1142 if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
1143 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
1144 if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
1145 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL));
1146 if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
1147 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP));
1148 if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
1149 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION));
1151 if (atoms.isEmpty()) {
1152 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_STATE));
1154 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
1155 atom(QXcbAtom::Atom_NET_WM_STATE), XCB_ATOM_ATOM, 32,
1156 atoms.size(), atoms.constData());
1158 xcb_flush(xcb_connection());
1161void QXcbWindow::setWindowState(Qt::WindowStates state)
1163 if (state == m_windowState)
1166 Qt::WindowStates unsetState = m_windowState & ~state;
1167 Qt::WindowStates newState = state & ~m_windowState;
1170 if (unsetState & Qt::WindowMinimized)
1171 xcb_map_window(xcb_connection(), m_window);
1172 if (unsetState & Qt::WindowMaximized)
1173 setNetWmState(
false,
1174 atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
1175 atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
1176 if (unsetState & Qt::WindowFullScreen)
1177 setNetWmState(
false, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
1180 if (newState & Qt::WindowMinimized) {
1182 xcb_client_message_event_t event;
1184 event.response_type = XCB_CLIENT_MESSAGE;
1187 event.window = m_window;
1188 event.type = atom(QXcbAtom::AtomWM_CHANGE_STATE);
1189 event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
1190 event.data.data32[1] = 0;
1191 event.data.data32[2] = 0;
1192 event.data.data32[3] = 0;
1193 event.data.data32[4] = 0;
1195 xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
1196 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
1197 (
const char *)&event);
1203 setNetWmState(state);
1205 xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window);
1206 xcb_icccm_wm_hints_t hints;
1207 if (xcb_icccm_get_wm_hints_reply(xcb_connection(), cookie, &hints,
nullptr)) {
1208 if (state & Qt::WindowMinimized)
1209 xcb_icccm_wm_hints_set_iconic(&hints);
1211 xcb_icccm_wm_hints_set_normal(&hints);
1212 xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints);
1215 connection()->sync();
1216 m_windowState = state;
1219void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
1221 xcb_window_t wid = m_window;
1226 connection()->setNetWmUserTime(timestamp);
1228 const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
1229 if (m_netWmUserTimeWindow || isSupportedByWM) {
1230 if (!m_netWmUserTimeWindow) {
1231 m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
1232 xcb_create_window(xcb_connection(),
1233 XCB_COPY_FROM_PARENT,
1234 m_netWmUserTimeWindow,
1238 XCB_WINDOW_CLASS_INPUT_OUTPUT,
1242 wid = m_netWmUserTimeWindow;
1243 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW),
1244 XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow);
1245 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME));
1247 QXcbWindow::setWindowTitle(connection(), m_netWmUserTimeWindow,
1248 QStringLiteral(
"Qt NET_WM User Time Window"));
1250 }
else if (!isSupportedByWM) {
1253 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
1254 xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
1255 m_netWmUserTimeWindow = XCB_NONE;
1257 wid = m_netWmUserTimeWindow;
1260 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::Atom_NET_WM_USER_TIME),
1261 XCB_ATOM_CARDINAL, 32, 1, ×tamp);
1417void QXcbWindow::propagateSizeHints()
1420 xcb_size_hints_t hints;
1421 memset(&hints, 0,
sizeof(hints));
1423 const QRect rect = geometry();
1424 QWindowPrivate *win = qt_window_private(window());
1426 if (!win->positionAutomatic)
1427 xcb_icccm_size_hints_set_position(&hints,
true, rect.x(), rect.y());
1428 if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX)
1429 xcb_icccm_size_hints_set_size(&hints,
true, rect.width(), rect.height());
1432
1433
1434
1435 auto gravity = win->positionPolicy == QWindowPrivate::WindowFrameInclusive
1436 ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC;
1438 xcb_icccm_size_hints_set_win_gravity(&hints, gravity);
1440 QSize minimumSize = windowMinimumSize();
1441 QSize maximumSize = windowMaximumSize();
1442 QSize baseSize = windowBaseSize();
1443 QSize sizeIncrement = windowSizeIncrement();
1445 if (minimumSize.width() > 0 || minimumSize.height() > 0)
1446 xcb_icccm_size_hints_set_min_size(&hints,
1450 if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
1451 xcb_icccm_size_hints_set_max_size(&hints,
1455 if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
1456 if (!baseSize.isNull() && baseSize.isValid())
1457 xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
1458 xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
1461 xcb_icccm_set_wm_normal_hints(xcb_connection(), m_window, &hints);
1463 m_sizeHintsScaleFactor = QHighDpiScaling::factor(screen());
1524QXcbWindow::WindowTypes QXcbWindow::wmWindowTypes()
const
1529 0, m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE),
1530 XCB_ATOM_ATOM, 0, 1024);
1531 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
1532 const xcb_atom_t *types =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
1533 const xcb_atom_t *types_end = types + reply->length;
1534 for (; types != types_end; types++) {
1535 QXcbAtom::Atom type = connection()->qatom(*types);
1537 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL:
1538 result |= WindowType::Normal;
1540 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP:
1541 result |= WindowType::Desktop;
1543 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK:
1544 result |= WindowType::Dock;
1546 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR:
1547 result |= WindowType::Toolbar;
1549 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU:
1550 result |= WindowType::Menu;
1552 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY:
1553 result |= WindowType::Utility;
1555 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH:
1556 result |= WindowType::Splash;
1558 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG:
1559 result |= WindowType::Dialog;
1561 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU:
1562 result |= WindowType::DropDownMenu;
1564 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU:
1565 result |= WindowType::PopupMenu;
1567 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP:
1568 result |= WindowType::Tooltip;
1570 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION:
1571 result |= WindowType::Notification;
1573 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO:
1574 result |= WindowType::Combo;
1576 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND:
1577 result |= WindowType::Dnd;
1579 case QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE:
1580 result |= WindowType::KdeOverride;
1590void QXcbWindow::setWmWindowType(WindowTypes types, Qt::WindowFlags flags)
1592 QList<xcb_atom_t> atoms;
1595 if (types & WindowType::Normal)
1596 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
1597 if (types & WindowType::Desktop)
1598 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP));
1599 if (types & WindowType::Dock)
1600 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK));
1601 if (types & WindowType::Notification)
1602 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION));
1605 if (types & WindowType::Utility)
1606 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
1607 if (types & WindowType::Splash)
1608 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
1609 if (types & WindowType::Dialog)
1610 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
1611 if (types & WindowType::Tooltip)
1612 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
1613 if (types & WindowType::KdeOverride)
1614 atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
1619 if (types & WindowType::Menu)
1620 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU));
1621 if (types & WindowType::DropDownMenu)
1622 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
1623 if (types & WindowType::PopupMenu)
1624 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU));
1625 if (types & WindowType::Toolbar)
1626 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR));
1627 if (types & WindowType::Combo)
1628 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO));
1629 if (types & WindowType::Dnd)
1630 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND));
1633 Qt::WindowType type =
static_cast<Qt::WindowType>(
int(flags & Qt::WindowType_Mask));
1637 if (!(types & WindowType::Dialog))
1638 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
1642 if (!(types & WindowType::Utility))
1643 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
1646 if (!(types & WindowType::Tooltip))
1647 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
1649 case Qt::SplashScreen:
1650 if (!(types & WindowType::Splash))
1651 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
1657 if ((flags & Qt::FramelessWindowHint) && !(types & WindowType::KdeOverride)) {
1659 atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
1662 if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL))
1665 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
1667 if (atoms.isEmpty()) {
1668 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE));
1670 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
1671 atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
1672 atoms.size(), atoms.constData());
1674 xcb_flush(xcb_connection());
1735void QXcbWindow::handleClientMessageEvent(
const xcb_client_message_event_t *event)
1737 if (event->format != 32)
1740 if (event->type == atom(QXcbAtom::AtomWM_PROTOCOLS)) {
1741 xcb_atom_t protocolAtom = event->data.data32[0];
1742 if (protocolAtom == atom(QXcbAtom::AtomWM_DELETE_WINDOW)) {
1743 QWindowSystemInterface::handleCloseEvent(window());
1744 }
else if (protocolAtom == atom(QXcbAtom::AtomWM_TAKE_FOCUS)) {
1745 connection()->setTime(event->data.data32[1]);
1746 relayFocusToModalWindow();
1748 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_PING)) {
1749 if (event->window == xcbScreen()->root())
1752 xcb_client_message_event_t reply = *event;
1754 reply.response_type = XCB_CLIENT_MESSAGE;
1755 reply.window = xcbScreen()->root();
1757 xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
1758 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
1759 (
const char *)&reply);
1760 xcb_flush(xcb_connection());
1761 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST)) {
1762 connection()->setTime(event->data.data32[1]);
1763 m_syncValue.lo = event->data.data32[2];
1764 m_syncValue.hi = event->data.data32[3];
1765 if (connection()->hasXSync())
1766 m_syncState = SyncReceived;
1767#ifndef QT_NO_WHATSTHIS
1768 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP)) {
1769 QWindowSystemInterface::handleEnterWhatsThisEvent();
1772 qCWarning(lcQpaXcb,
"Unhandled WM_PROTOCOLS (%s)",
1773 connection()->atomName(protocolAtom).constData());
1775#if QT_CONFIG(draganddrop)
1776 }
else if (event->type == atom(QXcbAtom::AtomXdndEnter)) {
1777 connection()->drag()->handleEnter(
this, event);
1778 }
else if (event->type == atom(QXcbAtom::AtomXdndPosition)) {
1779 connection()->drag()->handlePosition(
this, event);
1780 }
else if (event->type == atom(QXcbAtom::AtomXdndLeave)) {
1781 connection()->drag()->handleLeave(
this, event);
1782 }
else if (event->type == atom(QXcbAtom::AtomXdndDrop)) {
1783 connection()->drag()->handleDrop(
this, event);
1785 }
else if (event->type == atom(QXcbAtom::Atom_XEMBED)) {
1786 handleXEmbedMessage(event);
1787 }
else if (event->type == atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW)) {
1789 }
else if (event->type == atom(QXcbAtom::AtomMANAGER)
1790 || event->type == atom(QXcbAtom::Atom_NET_WM_STATE)
1791 || event->type == atom(QXcbAtom::AtomWM_CHANGE_STATE)) {
1794 }
else if (event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_PENDING)
1795 || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_REQUEST)
1796 || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_DELETE_PIXMAP)
1797 || event->type == atom(QXcbAtom::Atom_COMPIZ_TOOLKIT_ACTION)
1798 || event->type == atom(QXcbAtom::Atom_GTK_LOAD_ICONTHEMES)) {
1801 qCWarning(lcQpaXcb) <<
"Unhandled client message: " << connection()->atomName(event->type);
1917void QXcbWindow::handleButtonPressEvent(
int event_x,
int event_y,
int root_x,
int root_y,
1918 int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
1919 QEvent::Type type, Qt::MouseEventSource source)
1921 const bool isWheel = detail >= 4 && detail <= 7;
1922 if (!isWheel && window() != QGuiApplication::focusWindow()) {
1923 QWindow *w =
static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
1924 if (!(w->flags() & (Qt::WindowDoesNotAcceptFocus | Qt::BypassWindowManagerHint))
1925 && w->type() != Qt::ToolTip
1926 && w->type() != Qt::Popup) {
1927 w->requestActivate();
1931 updateNetWmUserTime(timestamp);
1933 if (m_embedded && !m_trayIconWindow) {
1934 if (window() != QGuiApplication::focusWindow()) {
1935 const QXcbWindow *container =
static_cast<
const QXcbWindow *>(QPlatformWindow::parent());
1936 Q_ASSERT(container !=
nullptr);
1938 sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
1941 QPoint local(event_x, event_y);
1942 QPoint global(root_x, root_y);
1945 if (!connection()->isAtLeastXI21()) {
1948 angleDelta.setY(120);
1949 else if (detail == 5)
1950 angleDelta.setY(-120);
1951 else if (detail == 6)
1952 angleDelta.setX(120);
1953 else if (detail == 7)
1954 angleDelta.setX(-120);
1955 if (modifiers & Qt::AltModifier)
1956 angleDelta = angleDelta.transposed();
1957 QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
1962 connection()->setMousePressWindow(
this);
1964 handleMouseEvent(timestamp, local, global, modifiers, type, source);
2122void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
2124 QXcbConnection *conn = connection();
2125 auto *ev =
reinterpret_cast<xcb_input_button_press_event_t *>(event);
2127 if (ev->buttons_len > 0) {
2128 unsigned char *buttonMask = (
unsigned char *) &ev[1];
2134 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2135 qCDebug(lcQpaXInput,
"XI2 mouse event from touch device %d was ignored", ev->sourceid);
2138 for (
int i = 1; i <= 15; ++i)
2139 conn->setButtonState(conn->translateMouseButton(i),
qt_xcb_mask_is_set(buttonMask, i));
2142 const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective);
2143 const int event_x = fixed1616ToInt(ev->event_x);
2144 const int event_y = fixed1616ToInt(ev->event_y);
2145 const int root_x = fixed1616ToInt(ev->root_x);
2146 const int root_y = fixed1616ToInt(ev->root_y);
2148 conn->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
2150 const Qt::MouseButton button = conn->xiToQtMouseButton(ev->detail);
2152 const char *sourceName =
nullptr;
2153 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
2154 const QMetaObject *metaObject = qt_getEnumMetaObject(source);
2155 const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(source)));
2156 sourceName = me.valueToKey(source);
2159 switch (ev->event_type) {
2160 case XCB_INPUT_BUTTON_PRESS:
2161 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2162 qCDebug(lcQpaXInputEvents,
"XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
2163 conn->setButtonState(button,
true);
2164 handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
2166 case XCB_INPUT_BUTTON_RELEASE:
2167 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2168 qCDebug(lcQpaXInputEvents,
"XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
2169 conn->setButtonState(button,
false);
2170 handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
2172 case XCB_INPUT_MOTION:
2173 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2174 qCDebug(lcQpaXInputEvents,
"XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName);
2175 handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
2178 qWarning() <<
"Unrecognized XI2 mouse event" << ev->event_type;
2240void QXcbWindow::handlePropertyNotifyEvent(
const xcb_property_notify_event_t *event)
2242 connection()->setTime(event->time);
2244 const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
2246 if (event->atom == atom(QXcbAtom::Atom_NET_WM_STATE) || event->atom == atom(QXcbAtom::AtomWM_STATE)) {
2247 if (propertyDeleted)
2250 Qt::WindowStates newState = Qt::WindowNoState;
2252 if (event->atom == atom(QXcbAtom::AtomWM_STATE)) {
2253 auto reply =
Q_XCB_REPLY(xcb_get_property, xcb_connection(),
2254 0, m_window, atom(QXcbAtom::AtomWM_STATE),
2255 XCB_ATOM_ANY, 0, 1024);
2256 if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::AtomWM_STATE)) {
2257 const quint32 *data = (
const quint32 *)xcb_get_property_value(reply.get());
2258 if (reply->length != 0)
2259 m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC
2260 || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
2264 const NetWmStates states = netWmStates();
2269 if (m_minimized && (!connection()->wmSupport()->isSupportedByWM(NetWmStateHidden)
2270 || states.testFlag(NetWmStateHidden)))
2271 newState = Qt::WindowMinimized;
2273 if (states & NetWmStateFullScreen)
2274 newState |= Qt::WindowFullScreen;
2275 if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
2276 newState |= Qt::WindowMaximized;
2278 if (m_lastWindowStateEvent != newState) {
2279 QWindowSystemInterface::handleWindowStateChanged(window(), newState);
2280 m_lastWindowStateEvent = newState;
2281 m_windowState = newState;
2282 if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() ==
this)
2283 connection()->setMouseGrabber(
nullptr);
2286 }
else if (event->atom == atom(QXcbAtom::Atom_NET_FRAME_EXTENTS)) {
2287 m_dirtyFrameMargins =
true;