229void QXcbWindow::create()
231 xcb_window_t old_m_window = m_window;
234 m_windowState = Qt::WindowNoState;
235 m_trayIconWindow = isTrayIconWindow(window());
237 Qt::WindowType type = window()->type();
239 QXcbScreen *currentScreen = xcbScreen();
240 QXcbScreen *platformScreen = QPlatformWindow::parent() ? parentScreen() : initialScreen();
241 QRect rect = QPlatformWindow::parent()
242 ? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen)
243 : QHighDpi::toNativePixels(window()->geometry(), platformScreen);
245 const QSize minimumSize = windowMinimumSize();
246 if (rect.width() > 0 || rect.height() > 0) {
247 rect.setWidth(qBound(1, rect.width(),
XCOORD_MAX));
248 rect.setHeight(qBound(1, rect.height(),
XCOORD_MAX));
249 }
else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
250 rect.setSize(minimumSize);
252 rect.setWidth(QHighDpi::toNativePixels(
int(defaultWindowWidth), platformScreen->QPlatformScreen::screen()));
253 rect.setHeight(QHighDpi::toNativePixels(
int(defaultWindowHeight), platformScreen->QPlatformScreen::screen()));
256 QPlatformWindow::setGeometry(rect);
258 if (platformScreen != currentScreen)
259 QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
261 xcb_window_t xcb_parent_id = platformScreen->root();
262 if (QPlatformWindow::parent()) {
263 xcb_parent_id =
static_cast<QXcbWindow *>(QPlatformWindow::parent())->xcb_window();
264 m_embedded = QPlatformWindow::parent()->isForeignWindow();
266 QSurfaceFormat parentFormat = QPlatformWindow::parent()->window()->requestedFormat();
267 if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) {
268 window()->setFormat(parentFormat);
272 resolveFormat(platformScreen->surfaceFormatFor(window()->requestedFormat()));
274 const xcb_visualtype_t *visual =
nullptr;
276 if (m_trayIconWindow && connection()->systemTrayTracker()) {
277 visual = platformScreen->visualForId(connection()->systemTrayTracker()->visualId());
278 }
else if (connection()->hasDefaultVisualId()) {
279 visual = platformScreen->visualForId(connection()->defaultVisualId());
281 qWarning() <<
"Failed to use requested visual id.";
284 if (QPlatformWindow::parent()) {
290 if (window()->surfaceType() == QSurface::VulkanSurface
291 && QPlatformWindow::parent()->window()->surfaceType() != QSurface::VulkanSurface)
293 visual = platformScreen->visualForId(
static_cast<QXcbWindow *>(QPlatformWindow::parent())->visualId());
298 visual = createVisual();
301 qWarning() <<
"Falling back to using screens root_visual.";
302 visual = platformScreen->visualForId(platformScreen->screen()->root_visual);
307 m_visualId = visual->visual_id;
308 m_depth = platformScreen->depthOfVisual(m_visualId);
309 setImageFormatForVisual(visual);
311 quint32 mask = XCB_CW_BACK_PIXMAP
312 | XCB_CW_BORDER_PIXEL
314 | XCB_CW_OVERRIDE_REDIRECT
320 XCB_BACK_PIXMAP_NONE,
321 platformScreen->screen()->black_pixel,
322 XCB_GRAVITY_NORTH_WEST,
323 type == Qt::Popup || type == Qt::ToolTip || (window()->flags() & Qt::BypassWindowManagerHint),
324 type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer,
326 platformScreen->colormapForVisual(m_visualId)
329 m_window = xcb_generate_id(xcb_connection());
330 xcb_create_window(xcb_connection(),
339 XCB_WINDOW_CLASS_INPUT_OUTPUT,
344 connection()->addWindowEventListener(m_window,
this);
346 propagateSizeHints();
348 xcb_atom_t properties[5];
349 int propertyCount = 0;
350 properties[propertyCount++] = atom(QXcbAtom::AtomWM_DELETE_WINDOW);
351 properties[propertyCount++] = atom(QXcbAtom::AtomWM_TAKE_FOCUS);
352 properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_PING);
354 if (connection()->hasXSync())
355 properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST);
357 if (window()->flags() & Qt::WindowContextHelpButtonHint)
358 properties[propertyCount++] = atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP);
360 xcb_change_property(xcb_connection(),
361 XCB_PROP_MODE_REPLACE,
363 atom(QXcbAtom::AtomWM_PROTOCOLS),
371 const QByteArray wmClass = QXcbIntegration::instance()->wmClass();
372 if (!wmClass.isEmpty()) {
373 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
374 m_window, atom(QXcbAtom::AtomWM_CLASS),
375 XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData());
378 QString desktopFileName = QGuiApplication::desktopFileName();
379 if (QGuiApplication::desktopFileName().isEmpty()) {
380 QFileInfo fi = QFileInfo(QCoreApplication::instance()->applicationFilePath());
381 QStringList domainName =
382 QCoreApplication::instance()->organizationDomain().split(QLatin1Char(
'.'),
385 if (domainName.isEmpty()) {
386 desktopFileName = fi.baseName();
388 for (
int i = 0; i < domainName.size(); ++i)
389 desktopFileName.prepend(QLatin1Char(
'.')).prepend(domainName.at(i));
390 desktopFileName.append(fi.baseName());
393 if (!desktopFileName.isEmpty()) {
394 const QByteArray dfName = desktopFileName.toUtf8();
395 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
396 m_window, atom(QXcbAtom::Atom_KDE_NET_WM_DESKTOP_FILE),
397 atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
398 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
399 m_window, atom(QXcbAtom::Atom_GTK_APPLICATION_ID),
400 atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
403 if (connection()->hasXSync()) {
404 m_syncCounter = xcb_generate_id(xcb_connection());
405 xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue);
407 xcb_change_property(xcb_connection(),
408 XCB_PROP_MODE_REPLACE,
410 atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST_COUNTER),
418 quint32 pid = getpid();
419 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
420 atom(QXcbAtom::Atom_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
423 const QByteArray clientMachine = QSysInfo::machineHostName().toLocal8Bit();
424 if (!clientMachine.isEmpty()) {
425 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
426 atom(QXcbAtom::AtomWM_CLIENT_MACHINE), XCB_ATOM_STRING, 8,
427 clientMachine.size(), clientMachine.constData());
432 xcb_icccm_wm_hints_t hints;
433 memset(&hints, 0,
sizeof(hints));
434 hints.flags = XCB_ICCCM_WM_HINT_WINDOW_GROUP;
435 hints.window_group = connection()->clientLeader();
436 xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints);
438 xcb_window_t leader = connection()->clientLeader();
439 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
440 atom(QXcbAtom::AtomWM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
444 quint32 data[] = { XEMBED_VERSION, XEMBED_MAPPED };
445 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
446 atom(QXcbAtom::Atom_XEMBED_INFO),
447 atom(QXcbAtom::Atom_XEMBED_INFO),
448 32, 2, (
void *)data);
450 if (connection()->hasXInput2())
451 connection()->xi2SelectDeviceEvents(m_window);
453 setWindowState(window()->windowStates());
454 setWindowFlags(window()->flags());
455 setWindowTitle(window()->title());
458 connection()->sync();
460#if QT_CONFIG(draganddrop)
461 connection()->drag()->dndEnable(
this,
true);
464 const qreal opacity = qt_window_private(window())->opacity;
465 if (!qFuzzyCompare(opacity, qreal(1.0)))
468 setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
470 if (window()->isTopLevel())
471 setWindowIcon(window()->icon());
473 if (window()->dynamicPropertyNames().contains(wm_window_role_property_id)) {
474 QByteArray wmWindowRole = window()->property(wm_window_role_property_id).toByteArray();
475 setWindowRole(QString::fromLatin1(wmWindowRole));
478 if (m_trayIconWindow)
479 m_embedded = requestSystemTrayWindowDock();
481 if (m_window != old_m_window) {
482 if (!m_wmTransientForChildren.isEmpty()) {
483 QList<QPointer<QXcbWindow>> transientChildren = m_wmTransientForChildren;
484 m_wmTransientForChildren.clear();
485 for (
auto transientChild : transientChildren) {
487 transientChild->updateWmTransientFor();
605QMargins QXcbWindow::frameMargins()
const
607 if (m_dirtyFrameMargins) {
608 if (connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_FRAME_EXTENTS))) {
609 auto reply =
Q_XCB_REPLY(xcb_get_property, xcb_connection(),
false, m_window,
610 atom(QXcbAtom::Atom_NET_FRAME_EXTENTS), XCB_ATOM_CARDINAL, 0, 4);
611 if (reply && reply->type == XCB_ATOM_CARDINAL && reply->format == 32 && reply->value_len == 4) {
612 quint32 *data = (quint32 *)xcb_get_property_value(reply.get());
614 m_frameMargins = QMargins(data[0], data[2], data[1], data[3]);
615 m_dirtyFrameMargins =
false;
616 return m_frameMargins;
622 xcb_window_t window = m_window;
623 xcb_window_t parent = m_window;
625 bool foundRoot =
false;
627 const QList<xcb_window_t> &virtualRoots =
628 connection()->wmSupport()->virtualRoots();
633 if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1 || reply->parent == XCB_WINDOW_NONE) {
637 parent = reply->parent;
640 m_dirtyFrameMargins =
false;
641 m_frameMargins = QMargins();
642 return m_frameMargins;
648 auto reply =
Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), window, parent, 0, 0);
650 offset = QPoint(reply->dst_x, reply->dst_y);
653 auto geom =
Q_XCB_REPLY(xcb_get_geometry, xcb_connection(), parent);
664 int left = offset.x() + geom->border_width;
665 int top = offset.y() + geom->border_width;
666 int right = geom->width + geom->border_width - geometry().width() - offset.x();
667 int bottom = geom->height + geom->border_width - geometry().height() - offset.y();
669 m_frameMargins = QMargins(left, top, right, bottom);
672 m_dirtyFrameMargins =
false;
675 return m_frameMargins;
889QXcbWindow::NetWmStates QXcbWindow::netWmStates()
894 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
895 XCB_ATOM_ATOM, 0, 1024);
897 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
898 const xcb_atom_t *states =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
899 const xcb_atom_t *statesEnd = states + reply->length;
900 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
901 result |= NetWmStateAbove;
902 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
903 result |= NetWmStateBelow;
904 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
905 result |= NetWmStateFullScreen;
906 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
907 result |= NetWmStateMaximizedHorz;
908 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
909 result |= NetWmStateMaximizedVert;
910 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
911 result |= NetWmStateModal;
912 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
913 result |= NetWmStateStaysOnTop;
914 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
915 result |= NetWmStateDemandsAttention;
916 if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
917 result |= NetWmStateHidden;
919 qCDebug(lcQpaXcb,
"getting net wm state (%x), empty\n", m_window);
964void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
966 Qt::WindowType type =
static_cast<Qt::WindowType>(
int(flags & Qt::WindowType_Mask));
968 QtMotifWmHints mwmhints;
969 memset(&mwmhints, 0,
sizeof(mwmhints));
971 if (type != Qt::SplashScreen) {
972 mwmhints.flags |= MWM_HINTS_DECORATIONS;
974 bool customize = flags & Qt::CustomizeWindowHint;
975 if (type == Qt::Window && !customize) {
976 const Qt::WindowFlags defaultFlags = Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
977 if (!(flags & defaultFlags))
978 flags |= defaultFlags;
980 if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
981 mwmhints.decorations |= MWM_DECOR_BORDER;
982 mwmhints.decorations |= MWM_DECOR_RESIZEH;
983 mwmhints.decorations |= MWM_DECOR_TITLE;
985 if (flags & Qt::WindowSystemMenuHint)
986 mwmhints.decorations |= MWM_DECOR_MENU;
988 if (flags & Qt::WindowMinimizeButtonHint) {
989 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
990 mwmhints.functions |= MWM_FUNC_MINIMIZE;
993 if (flags & Qt::WindowMaximizeButtonHint) {
994 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
995 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
998 if (flags & Qt::WindowCloseButtonHint)
999 mwmhints.functions |= MWM_FUNC_CLOSE;
1003 mwmhints.decorations = MWM_DECOR_ALL;
1006 if (mwmhints.functions != 0) {
1007 mwmhints.flags |= MWM_HINTS_FUNCTIONS;
1008 mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
1010 mwmhints.functions = MWM_FUNC_ALL;
1013 if (!(flags & Qt::FramelessWindowHint)
1014 && flags & Qt::CustomizeWindowHint
1015 && flags & Qt::WindowTitleHint
1017 (Qt::WindowMinimizeButtonHint
1018 | Qt::WindowMaximizeButtonHint
1019 | Qt::WindowCloseButtonHint)))
1022 mwmhints.flags = MWM_HINTS_FUNCTIONS;
1023 mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
1024 mwmhints.decorations = 0;
1027 if (mwmhints.flags) {
1028 xcb_change_property(xcb_connection(),
1029 XCB_PROP_MODE_REPLACE,
1031 atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
1032 atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
1037 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_MOTIF_WM_HINTS));
1081void QXcbWindow::setNetWmStateOnUnmappedWindow()
1083 QMutexLocker locker(&m_mappedMutex);
1084 if (Q_UNLIKELY(m_mapped))
1085 qCDebug(lcQpaXcb()) <<
"internal info: " << Q_FUNC_INFO <<
"called on mapped window";
1088 const Qt::WindowFlags flags = window()->flags();
1089 if (flags & Qt::WindowStaysOnTopHint) {
1090 states |= NetWmStateAbove;
1091 states |= NetWmStateStaysOnTop;
1092 }
else if (flags & Qt::WindowStaysOnBottomHint) {
1093 states |= NetWmStateBelow;
1096 if (window()->windowStates() & Qt::WindowMinimized)
1097 states |= NetWmStateHidden;
1099 if (window()->windowStates() & Qt::WindowFullScreen)
1100 states |= NetWmStateFullScreen;
1102 if (window()->windowStates() & Qt::WindowMaximized) {
1103 states |= NetWmStateMaximizedHorz;
1104 states |= NetWmStateMaximizedVert;
1107 if (window()->modality() != Qt::NonModal)
1108 states |= NetWmStateModal;
1118 QList<xcb_atom_t> atoms;
1120 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
1121 XCB_ATOM_ATOM, 0, 1024);
1122 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) {
1123 const xcb_atom_t *data =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
1124 atoms.resize(reply->value_len);
1125 memcpy((
void *)&atoms.first(), (
void *)data, reply->value_len *
sizeof(xcb_atom_t));
1128 if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
1129 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE));
1130 if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
1131 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW));
1132 if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
1133 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN));
1134 if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
1135 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
1136 if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
1137 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ));
1138 if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
1139 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
1140 if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
1141 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL));
1142 if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
1143 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP));
1144 if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
1145 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION));
1147 if (atoms.isEmpty()) {
1148 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_STATE));
1150 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
1151 atom(QXcbAtom::Atom_NET_WM_STATE), XCB_ATOM_ATOM, 32,
1152 atoms.size(), atoms.constData());
1154 xcb_flush(xcb_connection());
1157void QXcbWindow::setWindowState(Qt::WindowStates state)
1159 if (state == m_windowState)
1162 Qt::WindowStates unsetState = m_windowState & ~state;
1163 Qt::WindowStates newState = state & ~m_windowState;
1166 if (unsetState & Qt::WindowMinimized)
1167 xcb_map_window(xcb_connection(), m_window);
1168 if (unsetState & Qt::WindowMaximized)
1169 setNetWmState(
false,
1170 atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
1171 atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
1172 if (unsetState & Qt::WindowFullScreen)
1173 setNetWmState(
false, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
1176 if (newState & Qt::WindowMinimized) {
1178 xcb_client_message_event_t event;
1180 event.response_type = XCB_CLIENT_MESSAGE;
1183 event.window = m_window;
1184 event.type = atom(QXcbAtom::AtomWM_CHANGE_STATE);
1185 event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
1186 event.data.data32[1] = 0;
1187 event.data.data32[2] = 0;
1188 event.data.data32[3] = 0;
1189 event.data.data32[4] = 0;
1191 xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
1192 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
1193 (
const char *)&event);
1199 setNetWmState(state);
1201 xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window);
1202 xcb_icccm_wm_hints_t hints;
1203 if (xcb_icccm_get_wm_hints_reply(xcb_connection(), cookie, &hints,
nullptr)) {
1204 if (state & Qt::WindowMinimized)
1205 xcb_icccm_wm_hints_set_iconic(&hints);
1207 xcb_icccm_wm_hints_set_normal(&hints);
1208 xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints);
1211 connection()->sync();
1212 m_windowState = state;
1215void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
1217 xcb_window_t wid = m_window;
1222 connection()->setNetWmUserTime(timestamp);
1224 const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
1225 if (m_netWmUserTimeWindow || isSupportedByWM) {
1226 if (!m_netWmUserTimeWindow) {
1227 m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
1228 xcb_create_window(xcb_connection(),
1229 XCB_COPY_FROM_PARENT,
1230 m_netWmUserTimeWindow,
1234 XCB_WINDOW_CLASS_INPUT_OUTPUT,
1238 wid = m_netWmUserTimeWindow;
1239 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW),
1240 XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow);
1241 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME));
1243 QXcbWindow::setWindowTitle(connection(), m_netWmUserTimeWindow,
1244 QStringLiteral(
"Qt NET_WM User Time Window"));
1246 }
else if (!isSupportedByWM) {
1249 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
1250 xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
1251 m_netWmUserTimeWindow = XCB_NONE;
1253 wid = m_netWmUserTimeWindow;
1256 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::Atom_NET_WM_USER_TIME),
1257 XCB_ATOM_CARDINAL, 32, 1, ×tamp);
1413void QXcbWindow::propagateSizeHints()
1416 xcb_size_hints_t hints;
1417 memset(&hints, 0,
sizeof(hints));
1419 const QRect rect = geometry();
1420 QWindowPrivate *win = qt_window_private(window());
1422 if (!win->positionAutomatic)
1423 xcb_icccm_size_hints_set_position(&hints,
true, rect.x(), rect.y());
1424 if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX)
1425 xcb_icccm_size_hints_set_size(&hints,
true, rect.width(), rect.height());
1428
1429
1430
1431 auto gravity = win->positionPolicy == QWindowPrivate::WindowFrameInclusive
1432 ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC;
1434 xcb_icccm_size_hints_set_win_gravity(&hints, gravity);
1436 QSize minimumSize = windowMinimumSize();
1437 QSize maximumSize = windowMaximumSize();
1438 QSize baseSize = windowBaseSize();
1439 QSize sizeIncrement = windowSizeIncrement();
1441 if (minimumSize.width() > 0 || minimumSize.height() > 0)
1442 xcb_icccm_size_hints_set_min_size(&hints,
1446 if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
1447 xcb_icccm_size_hints_set_max_size(&hints,
1451 if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
1452 if (!baseSize.isNull() && baseSize.isValid())
1453 xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
1454 xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
1457 xcb_icccm_set_wm_normal_hints(xcb_connection(), m_window, &hints);
1459 m_sizeHintsScaleFactor = QHighDpiScaling::factor(screen());
1520QXcbWindow::WindowTypes QXcbWindow::wmWindowTypes()
const
1525 0, m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE),
1526 XCB_ATOM_ATOM, 0, 1024);
1527 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
1528 const xcb_atom_t *types =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
1529 const xcb_atom_t *types_end = types + reply->length;
1530 for (; types != types_end; types++) {
1531 QXcbAtom::Atom type = connection()->qatom(*types);
1533 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL:
1534 result |= WindowType::Normal;
1536 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP:
1537 result |= WindowType::Desktop;
1539 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK:
1540 result |= WindowType::Dock;
1542 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR:
1543 result |= WindowType::Toolbar;
1545 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU:
1546 result |= WindowType::Menu;
1548 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY:
1549 result |= WindowType::Utility;
1551 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH:
1552 result |= WindowType::Splash;
1554 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG:
1555 result |= WindowType::Dialog;
1557 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU:
1558 result |= WindowType::DropDownMenu;
1560 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU:
1561 result |= WindowType::PopupMenu;
1563 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP:
1564 result |= WindowType::Tooltip;
1566 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION:
1567 result |= WindowType::Notification;
1569 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO:
1570 result |= WindowType::Combo;
1572 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND:
1573 result |= WindowType::Dnd;
1575 case QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE:
1576 result |= WindowType::KdeOverride;
1586void QXcbWindow::setWmWindowType(WindowTypes types, Qt::WindowFlags flags)
1588 QList<xcb_atom_t> atoms;
1591 if (types & WindowType::Normal)
1592 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
1593 if (types & WindowType::Desktop)
1594 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP));
1595 if (types & WindowType::Dock)
1596 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK));
1597 if (types & WindowType::Notification)
1598 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION));
1601 if (types & WindowType::Utility)
1602 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
1603 if (types & WindowType::Splash)
1604 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
1605 if (types & WindowType::Dialog)
1606 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
1607 if (types & WindowType::Tooltip)
1608 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
1609 if (types & WindowType::KdeOverride)
1610 atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
1615 if (types & WindowType::Menu)
1616 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU));
1617 if (types & WindowType::DropDownMenu)
1618 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
1619 if (types & WindowType::PopupMenu)
1620 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU));
1621 if (types & WindowType::Toolbar)
1622 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR));
1623 if (types & WindowType::Combo)
1624 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO));
1625 if (types & WindowType::Dnd)
1626 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND));
1629 Qt::WindowType type =
static_cast<Qt::WindowType>(
int(flags & Qt::WindowType_Mask));
1633 if (!(types & WindowType::Dialog))
1634 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
1638 if (!(types & WindowType::Utility))
1639 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
1642 if (!(types & WindowType::Tooltip))
1643 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
1645 case Qt::SplashScreen:
1646 if (!(types & WindowType::Splash))
1647 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
1653 if ((flags & Qt::FramelessWindowHint) && !(types & WindowType::KdeOverride)) {
1655 atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
1658 if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL))
1661 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
1663 if (atoms.isEmpty()) {
1664 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE));
1666 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
1667 atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
1668 atoms.size(), atoms.constData());
1670 xcb_flush(xcb_connection());
1731void QXcbWindow::handleClientMessageEvent(
const xcb_client_message_event_t *event)
1733 if (event->format != 32)
1736 if (event->type == atom(QXcbAtom::AtomWM_PROTOCOLS)) {
1737 xcb_atom_t protocolAtom = event->data.data32[0];
1738 if (protocolAtom == atom(QXcbAtom::AtomWM_DELETE_WINDOW)) {
1739 QWindowSystemInterface::handleCloseEvent(window());
1740 }
else if (protocolAtom == atom(QXcbAtom::AtomWM_TAKE_FOCUS)) {
1741 connection()->setTime(event->data.data32[1]);
1742 relayFocusToModalWindow();
1744 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_PING)) {
1745 if (event->window == xcbScreen()->root())
1748 xcb_client_message_event_t reply = *event;
1750 reply.response_type = XCB_CLIENT_MESSAGE;
1751 reply.window = xcbScreen()->root();
1753 xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
1754 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
1755 (
const char *)&reply);
1756 xcb_flush(xcb_connection());
1757 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST)) {
1758 connection()->setTime(event->data.data32[1]);
1759 m_syncValue.lo = event->data.data32[2];
1760 m_syncValue.hi = event->data.data32[3];
1761 if (connection()->hasXSync())
1762 m_syncState = SyncReceived;
1763#ifndef QT_NO_WHATSTHIS
1764 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP)) {
1765 QWindowSystemInterface::handleEnterWhatsThisEvent();
1768 qCWarning(lcQpaXcb,
"Unhandled WM_PROTOCOLS (%s)",
1769 connection()->atomName(protocolAtom).constData());
1771#if QT_CONFIG(draganddrop)
1772 }
else if (event->type == atom(QXcbAtom::AtomXdndEnter)) {
1773 connection()->drag()->handleEnter(
this, event);
1774 }
else if (event->type == atom(QXcbAtom::AtomXdndPosition)) {
1775 connection()->drag()->handlePosition(
this, event);
1776 }
else if (event->type == atom(QXcbAtom::AtomXdndLeave)) {
1777 connection()->drag()->handleLeave(
this, event);
1778 }
else if (event->type == atom(QXcbAtom::AtomXdndDrop)) {
1779 connection()->drag()->handleDrop(
this, event);
1781 }
else if (event->type == atom(QXcbAtom::Atom_XEMBED)) {
1782 handleXEmbedMessage(event);
1783 }
else if (event->type == atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW)) {
1785 }
else if (event->type == atom(QXcbAtom::AtomMANAGER)
1786 || event->type == atom(QXcbAtom::Atom_NET_WM_STATE)
1787 || event->type == atom(QXcbAtom::AtomWM_CHANGE_STATE)) {
1790 }
else if (event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_PENDING)
1791 || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_REQUEST)
1792 || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_DELETE_PIXMAP)
1793 || event->type == atom(QXcbAtom::Atom_COMPIZ_TOOLKIT_ACTION)
1794 || event->type == atom(QXcbAtom::Atom_GTK_LOAD_ICONTHEMES)) {
1797 qCWarning(lcQpaXcb) <<
"Unhandled client message: " << connection()->atomName(event->type);
1913void QXcbWindow::handleButtonPressEvent(
int event_x,
int event_y,
int root_x,
int root_y,
1914 int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
1915 QEvent::Type type, Qt::MouseEventSource source)
1917 const bool isWheel = detail >= 4 && detail <= 7;
1918 if (!isWheel && window() != QGuiApplication::focusWindow()) {
1919 QWindow *w =
static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
1920 if (!(w->flags() & (Qt::WindowDoesNotAcceptFocus | Qt::BypassWindowManagerHint))
1921 && w->type() != Qt::ToolTip
1922 && w->type() != Qt::Popup) {
1923 w->requestActivate();
1927 updateNetWmUserTime(timestamp);
1929 if (m_embedded && !m_trayIconWindow) {
1930 if (window() != QGuiApplication::focusWindow()) {
1931 const QXcbWindow *container =
static_cast<
const QXcbWindow *>(QPlatformWindow::parent());
1932 Q_ASSERT(container !=
nullptr);
1934 sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
1937 QPoint local(event_x, event_y);
1938 QPoint global(root_x, root_y);
1941 if (!connection()->isAtLeastXI21()) {
1944 angleDelta.setY(120);
1945 else if (detail == 5)
1946 angleDelta.setY(-120);
1947 else if (detail == 6)
1948 angleDelta.setX(120);
1949 else if (detail == 7)
1950 angleDelta.setX(-120);
1951 if (modifiers & Qt::AltModifier)
1952 angleDelta = angleDelta.transposed();
1953 QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
1958 connection()->setMousePressWindow(
this);
1960 handleMouseEvent(timestamp, local, global, modifiers, type, source);
2118void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
2120 QXcbConnection *conn = connection();
2121 auto *ev =
reinterpret_cast<xcb_input_button_press_event_t *>(event);
2123 if (ev->buttons_len > 0) {
2124 unsigned char *buttonMask = (
unsigned char *) &ev[1];
2130 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2131 qCDebug(lcQpaXInput,
"XI2 mouse event from touch device %d was ignored", ev->sourceid);
2134 for (
int i = 1; i <= 15; ++i)
2135 conn->setButtonState(conn->translateMouseButton(i),
qt_xcb_mask_is_set(buttonMask, i));
2138 const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective);
2139 const int event_x = fixed1616ToInt(ev->event_x);
2140 const int event_y = fixed1616ToInt(ev->event_y);
2141 const int root_x = fixed1616ToInt(ev->root_x);
2142 const int root_y = fixed1616ToInt(ev->root_y);
2144 conn->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
2146 const Qt::MouseButton button = conn->xiToQtMouseButton(ev->detail);
2148 const char *sourceName =
nullptr;
2149 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
2150 const QMetaObject *metaObject = qt_getEnumMetaObject(source);
2151 const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(source)));
2152 sourceName = me.valueToKey(source);
2155 switch (ev->event_type) {
2156 case XCB_INPUT_BUTTON_PRESS:
2157 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2158 qCDebug(lcQpaXInputEvents,
"XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
2159 conn->setButtonState(button,
true);
2160 handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
2162 case XCB_INPUT_BUTTON_RELEASE:
2163 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2164 qCDebug(lcQpaXInputEvents,
"XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
2165 conn->setButtonState(button,
false);
2166 handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
2168 case XCB_INPUT_MOTION:
2169 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2170 qCDebug(lcQpaXInputEvents,
"XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName);
2171 handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
2174 qWarning() <<
"Unrecognized XI2 mouse event" << ev->event_type;
2236void QXcbWindow::handlePropertyNotifyEvent(
const xcb_property_notify_event_t *event)
2238 connection()->setTime(event->time);
2240 const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
2242 if (event->atom == atom(QXcbAtom::Atom_NET_WM_STATE) || event->atom == atom(QXcbAtom::AtomWM_STATE)) {
2243 if (propertyDeleted)
2246 Qt::WindowStates newState = Qt::WindowNoState;
2248 if (event->atom == atom(QXcbAtom::AtomWM_STATE)) {
2249 auto reply =
Q_XCB_REPLY(xcb_get_property, xcb_connection(),
2250 0, m_window, atom(QXcbAtom::AtomWM_STATE),
2251 XCB_ATOM_ANY, 0, 1024);
2252 if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::AtomWM_STATE)) {
2253 const quint32 *data = (
const quint32 *)xcb_get_property_value(reply.get());
2254 if (reply->length != 0)
2255 m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC
2256 || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
2260 const NetWmStates states = netWmStates();
2265 if (m_minimized && (!connection()->wmSupport()->isSupportedByWM(NetWmStateHidden)
2266 || states.testFlag(NetWmStateHidden)))
2267 newState = Qt::WindowMinimized;
2269 if (states & NetWmStateFullScreen)
2270 newState |= Qt::WindowFullScreen;
2271 if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
2272 newState |= Qt::WindowMaximized;
2274 if (m_lastWindowStateEvent != newState) {
2275 QWindowSystemInterface::handleWindowStateChanged(window(), newState);
2276 m_lastWindowStateEvent = newState;
2277 m_windowState = newState;
2278 if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() ==
this)
2279 connection()->setMouseGrabber(
nullptr);
2282 }
else if (event->atom == atom(QXcbAtom::Atom_NET_FRAME_EXTENTS)) {
2283 m_dirtyFrameMargins =
true;