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);
969void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
971 Qt::WindowType type =
static_cast<Qt::WindowType>(
int(flags & Qt::WindowType_Mask));
973 QtMotifWmHints mwmhints;
974 memset(&mwmhints, 0,
sizeof(mwmhints));
976 if (type != Qt::SplashScreen) {
977 mwmhints.flags |= MWM_HINTS_DECORATIONS;
979 bool customize = flags & Qt::CustomizeWindowHint;
980 if (type == Qt::Window && !customize) {
981 const Qt::WindowFlags defaultFlags = Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
982 if (!(flags & defaultFlags))
983 flags |= defaultFlags;
985 if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
986 mwmhints.decorations |= MWM_DECOR_BORDER;
987 mwmhints.decorations |= MWM_DECOR_RESIZEH;
988 mwmhints.decorations |= MWM_DECOR_TITLE;
990 if (flags & Qt::WindowSystemMenuHint)
991 mwmhints.decorations |= MWM_DECOR_MENU;
993 if (flags & Qt::WindowMinimizeButtonHint) {
994 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
995 mwmhints.functions |= MWM_FUNC_MINIMIZE;
998 if (flags & Qt::WindowMaximizeButtonHint) {
999 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
1000 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
1003 if (flags & Qt::WindowCloseButtonHint)
1004 mwmhints.functions |= MWM_FUNC_CLOSE;
1008 mwmhints.decorations = MWM_DECOR_ALL;
1011 if (mwmhints.functions != 0) {
1012 mwmhints.flags |= MWM_HINTS_FUNCTIONS;
1013 mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
1015 mwmhints.functions = MWM_FUNC_ALL;
1018 if (!(flags & Qt::FramelessWindowHint)
1019 && flags & Qt::CustomizeWindowHint
1020 && flags & Qt::WindowTitleHint
1022 (Qt::WindowMinimizeButtonHint
1023 | Qt::WindowMaximizeButtonHint
1024 | Qt::WindowCloseButtonHint)))
1027 mwmhints.flags = MWM_HINTS_FUNCTIONS;
1028 mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
1029 mwmhints.decorations = 0;
1032 if (mwmhints.flags) {
1033 xcb_change_property(xcb_connection(),
1034 XCB_PROP_MODE_REPLACE,
1036 atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
1037 atom(QXcbAtom::Atom_MOTIF_WM_HINTS),
1042 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_MOTIF_WM_HINTS));
1086void QXcbWindow::setNetWmStateOnUnmappedWindow()
1088 QMutexLocker locker(&m_mappedMutex);
1089 if (Q_UNLIKELY(m_mapped))
1090 qCDebug(lcQpaXcb()) <<
"internal info: " << Q_FUNC_INFO <<
"called on mapped window";
1093 const Qt::WindowFlags flags = window()->flags();
1094 if (flags & Qt::WindowStaysOnTopHint) {
1095 states |= NetWmStateAbove;
1096 states |= NetWmStateStaysOnTop;
1097 }
else if (flags & Qt::WindowStaysOnBottomHint) {
1098 states |= NetWmStateBelow;
1101 if (window()->windowStates() & Qt::WindowMinimized)
1102 states |= NetWmStateHidden;
1104 if (window()->windowStates() & Qt::WindowFullScreen)
1105 states |= NetWmStateFullScreen;
1107 if (window()->windowStates() & Qt::WindowMaximized) {
1108 states |= NetWmStateMaximizedHorz;
1109 states |= NetWmStateMaximizedVert;
1112 if (window()->modality() != Qt::NonModal)
1113 states |= NetWmStateModal;
1123 QList<xcb_atom_t> atoms;
1125 0, m_window, atom(QXcbAtom::Atom_NET_WM_STATE),
1126 XCB_ATOM_ATOM, 0, 1024);
1127 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM && reply->value_len > 0) {
1128 const xcb_atom_t *data =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
1129 atoms.resize(reply->value_len);
1130 memcpy((
void *)&atoms.first(), (
void *)data, reply->value_len *
sizeof(xcb_atom_t));
1133 if (states & NetWmStateAbove && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE)))
1134 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_ABOVE));
1135 if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW)))
1136 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_BELOW));
1137 if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN)))
1138 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_HIDDEN));
1139 if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN)))
1140 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
1141 if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ)))
1142 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ));
1143 if (states & NetWmStateMaximizedVert && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT)))
1144 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
1145 if (states & NetWmStateModal && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL)))
1146 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_MODAL));
1147 if (states & NetWmStateStaysOnTop && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP)))
1148 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_STAYS_ON_TOP));
1149 if (states & NetWmStateDemandsAttention && !atoms.contains(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION)))
1150 atoms.push_back(atom(QXcbAtom::Atom_NET_WM_STATE_DEMANDS_ATTENTION));
1152 if (atoms.isEmpty()) {
1153 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_STATE));
1155 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
1156 atom(QXcbAtom::Atom_NET_WM_STATE), XCB_ATOM_ATOM, 32,
1157 atoms.size(), atoms.constData());
1159 xcb_flush(xcb_connection());
1162void QXcbWindow::setWindowState(Qt::WindowStates state)
1164 if (state == m_windowState)
1167 Qt::WindowStates unsetState = m_windowState & ~state;
1168 Qt::WindowStates newState = state & ~m_windowState;
1171 if (unsetState & Qt::WindowMinimized)
1172 xcb_map_window(xcb_connection(), m_window);
1173 if (unsetState & Qt::WindowMaximized)
1174 setNetWmState(
false,
1175 atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
1176 atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
1177 if (unsetState & Qt::WindowFullScreen)
1178 setNetWmState(
false, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
1181 if (newState & Qt::WindowMinimized) {
1183 xcb_client_message_event_t event;
1185 event.response_type = XCB_CLIENT_MESSAGE;
1188 event.window = m_window;
1189 event.type = atom(QXcbAtom::AtomWM_CHANGE_STATE);
1190 event.data.data32[0] = XCB_ICCCM_WM_STATE_ICONIC;
1191 event.data.data32[1] = 0;
1192 event.data.data32[2] = 0;
1193 event.data.data32[3] = 0;
1194 event.data.data32[4] = 0;
1196 xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
1197 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
1198 (
const char *)&event);
1204 setNetWmState(state);
1206 xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window);
1207 xcb_icccm_wm_hints_t hints;
1208 if (xcb_icccm_get_wm_hints_reply(xcb_connection(), cookie, &hints,
nullptr)) {
1209 if (state & Qt::WindowMinimized)
1210 xcb_icccm_wm_hints_set_iconic(&hints);
1212 xcb_icccm_wm_hints_set_normal(&hints);
1213 xcb_icccm_set_wm_hints(xcb_connection(), m_window, &hints);
1216 connection()->sync();
1217 m_windowState = state;
1220void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
1222 xcb_window_t wid = m_window;
1227 connection()->setNetWmUserTime(timestamp);
1229 const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
1230 if (m_netWmUserTimeWindow || isSupportedByWM) {
1231 if (!m_netWmUserTimeWindow) {
1232 m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
1233 xcb_create_window(xcb_connection(),
1234 XCB_COPY_FROM_PARENT,
1235 m_netWmUserTimeWindow,
1239 XCB_WINDOW_CLASS_INPUT_OUTPUT,
1243 wid = m_netWmUserTimeWindow;
1244 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW),
1245 XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow);
1246 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME));
1248 QXcbWindow::setWindowTitle(connection(), m_netWmUserTimeWindow,
1249 QStringLiteral(
"Qt NET_WM User Time Window"));
1251 }
else if (!isSupportedByWM) {
1254 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_USER_TIME_WINDOW));
1255 xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
1256 m_netWmUserTimeWindow = XCB_NONE;
1258 wid = m_netWmUserTimeWindow;
1261 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::Atom_NET_WM_USER_TIME),
1262 XCB_ATOM_CARDINAL, 32, 1, ×tamp);
1418void QXcbWindow::propagateSizeHints()
1421 xcb_size_hints_t hints;
1422 memset(&hints, 0,
sizeof(hints));
1424 const QRect rect = geometry();
1425 QWindowPrivate *win = qt_window_private(window());
1427 if (!win->positionAutomatic)
1428 xcb_icccm_size_hints_set_position(&hints,
true, rect.x(), rect.y());
1429 if (rect.width() < QWINDOWSIZE_MAX || rect.height() < QWINDOWSIZE_MAX)
1430 xcb_icccm_size_hints_set_size(&hints,
true, rect.width(), rect.height());
1433
1434
1435
1436 auto gravity = win->positionPolicy == QWindowPrivate::WindowFrameInclusive
1437 ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC;
1439 xcb_icccm_size_hints_set_win_gravity(&hints, gravity);
1441 QSize minimumSize = windowMinimumSize();
1442 QSize maximumSize = windowMaximumSize();
1443 QSize baseSize = windowBaseSize();
1444 QSize sizeIncrement = windowSizeIncrement();
1446 if (minimumSize.width() > 0 || minimumSize.height() > 0)
1447 xcb_icccm_size_hints_set_min_size(&hints,
1451 if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
1452 xcb_icccm_size_hints_set_max_size(&hints,
1456 if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
1457 if (!baseSize.isNull() && baseSize.isValid())
1458 xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
1459 xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
1462 xcb_icccm_set_wm_normal_hints(xcb_connection(), m_window, &hints);
1464 m_sizeHintsScaleFactor = QHighDpiScaling::factor(screen());
1525QXcbWindow::WindowTypes QXcbWindow::wmWindowTypes()
const
1530 0, m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE),
1531 XCB_ATOM_ATOM, 0, 1024);
1532 if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
1533 const xcb_atom_t *types =
static_cast<
const xcb_atom_t *>(xcb_get_property_value(reply.get()));
1534 const xcb_atom_t *types_end = types + reply->length;
1535 for (; types != types_end; types++) {
1536 QXcbAtom::Atom type = connection()->qatom(*types);
1538 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL:
1539 result |= WindowType::Normal;
1541 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP:
1542 result |= WindowType::Desktop;
1544 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK:
1545 result |= WindowType::Dock;
1547 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR:
1548 result |= WindowType::Toolbar;
1550 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU:
1551 result |= WindowType::Menu;
1553 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY:
1554 result |= WindowType::Utility;
1556 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH:
1557 result |= WindowType::Splash;
1559 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG:
1560 result |= WindowType::Dialog;
1562 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU:
1563 result |= WindowType::DropDownMenu;
1565 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU:
1566 result |= WindowType::PopupMenu;
1568 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP:
1569 result |= WindowType::Tooltip;
1571 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION:
1572 result |= WindowType::Notification;
1574 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO:
1575 result |= WindowType::Combo;
1577 case QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND:
1578 result |= WindowType::Dnd;
1580 case QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE:
1581 result |= WindowType::KdeOverride;
1591void QXcbWindow::setWmWindowType(WindowTypes types, Qt::WindowFlags flags)
1593 QList<xcb_atom_t> atoms;
1596 if (types & WindowType::Normal)
1597 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
1598 if (types & WindowType::Desktop)
1599 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DESKTOP));
1600 if (types & WindowType::Dock)
1601 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DOCK));
1602 if (types & WindowType::Notification)
1603 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NOTIFICATION));
1606 if (types & WindowType::Utility)
1607 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
1608 if (types & WindowType::Splash)
1609 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
1610 if (types & WindowType::Dialog)
1611 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
1612 if (types & WindowType::Tooltip)
1613 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
1614 if (types & WindowType::KdeOverride)
1615 atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
1620 if (types & WindowType::Menu)
1621 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_MENU));
1622 if (types & WindowType::DropDownMenu)
1623 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DROPDOWN_MENU));
1624 if (types & WindowType::PopupMenu)
1625 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_POPUP_MENU));
1626 if (types & WindowType::Toolbar)
1627 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLBAR));
1628 if (types & WindowType::Combo)
1629 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_COMBO));
1630 if (types & WindowType::Dnd)
1631 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DND));
1634 Qt::WindowType type =
static_cast<Qt::WindowType>(
int(flags & Qt::WindowType_Mask));
1638 if (!(types & WindowType::Dialog))
1639 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_DIALOG));
1643 if (!(types & WindowType::Utility))
1644 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_UTILITY));
1647 if (!(types & WindowType::Tooltip))
1648 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_TOOLTIP));
1650 case Qt::SplashScreen:
1651 if (!(types & WindowType::Splash))
1652 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_SPLASH));
1658 if ((flags & Qt::FramelessWindowHint) && !(types & WindowType::KdeOverride)) {
1660 atoms.append(atom(QXcbAtom::Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
1663 if (atoms.size() == 1 && atoms.first() == atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL))
1666 atoms.append(atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE_NORMAL));
1668 if (atoms.isEmpty()) {
1669 xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE));
1671 xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
1672 atom(QXcbAtom::Atom_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
1673 atoms.size(), atoms.constData());
1675 xcb_flush(xcb_connection());
1736void QXcbWindow::handleClientMessageEvent(
const xcb_client_message_event_t *event)
1738 if (event->format != 32)
1741 if (event->type == atom(QXcbAtom::AtomWM_PROTOCOLS)) {
1742 xcb_atom_t protocolAtom = event->data.data32[0];
1743 if (protocolAtom == atom(QXcbAtom::AtomWM_DELETE_WINDOW)) {
1744 QWindowSystemInterface::handleCloseEvent(window());
1745 }
else if (protocolAtom == atom(QXcbAtom::AtomWM_TAKE_FOCUS)) {
1746 connection()->setTime(event->data.data32[1]);
1747 relayFocusToModalWindow();
1749 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_PING)) {
1750 if (event->window == xcbScreen()->root())
1753 xcb_client_message_event_t reply = *event;
1755 reply.response_type = XCB_CLIENT_MESSAGE;
1756 reply.window = xcbScreen()->root();
1758 xcb_send_event(xcb_connection(), 0, xcbScreen()->root(),
1759 XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
1760 (
const char *)&reply);
1761 xcb_flush(xcb_connection());
1762 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_SYNC_REQUEST)) {
1763 connection()->setTime(event->data.data32[1]);
1764 m_syncValue.lo = event->data.data32[2];
1765 m_syncValue.hi = event->data.data32[3];
1766 if (connection()->hasXSync())
1767 m_syncState = SyncReceived;
1768#ifndef QT_NO_WHATSTHIS
1769 }
else if (protocolAtom == atom(QXcbAtom::Atom_NET_WM_CONTEXT_HELP)) {
1770 QWindowSystemInterface::handleEnterWhatsThisEvent();
1773 qCWarning(lcQpaXcb,
"Unhandled WM_PROTOCOLS (%s)",
1774 connection()->atomName(protocolAtom).constData());
1776#if QT_CONFIG(draganddrop)
1777 }
else if (event->type == atom(QXcbAtom::AtomXdndEnter)) {
1778 connection()->drag()->handleEnter(
this, event);
1779 }
else if (event->type == atom(QXcbAtom::AtomXdndPosition)) {
1780 connection()->drag()->handlePosition(
this, event);
1781 }
else if (event->type == atom(QXcbAtom::AtomXdndLeave)) {
1782 connection()->drag()->handleLeave(
this, event);
1783 }
else if (event->type == atom(QXcbAtom::AtomXdndDrop)) {
1784 connection()->drag()->handleDrop(
this, event);
1786 }
else if (event->type == atom(QXcbAtom::Atom_XEMBED)) {
1787 handleXEmbedMessage(event);
1788 }
else if (event->type == atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW)) {
1790 }
else if (event->type == atom(QXcbAtom::AtomMANAGER)
1791 || event->type == atom(QXcbAtom::Atom_NET_WM_STATE)
1792 || event->type == atom(QXcbAtom::AtomWM_CHANGE_STATE)) {
1795 }
else if (event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_PENDING)
1796 || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_REQUEST)
1797 || event->type == atom(QXcbAtom::Atom_COMPIZ_DECOR_DELETE_PIXMAP)
1798 || event->type == atom(QXcbAtom::Atom_COMPIZ_TOOLKIT_ACTION)
1799 || event->type == atom(QXcbAtom::Atom_GTK_LOAD_ICONTHEMES)) {
1802 qCWarning(lcQpaXcb) <<
"Unhandled client message: " << connection()->atomName(event->type);
1918void QXcbWindow::handleButtonPressEvent(
int event_x,
int event_y,
int root_x,
int root_y,
1919 int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp,
1920 QEvent::Type type, Qt::MouseEventSource source)
1922 const bool isWheel = detail >= 4 && detail <= 7;
1923 if (!isWheel && window() != QGuiApplication::focusWindow()) {
1924 QWindow *w =
static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
1925 if (!(w->flags() & (Qt::WindowDoesNotAcceptFocus | Qt::BypassWindowManagerHint))
1926 && w->type() != Qt::ToolTip
1927 && w->type() != Qt::Popup) {
1928 w->requestActivate();
1932 updateNetWmUserTime(timestamp);
1934 if (m_embedded && !m_trayIconWindow) {
1935 if (window() != QGuiApplication::focusWindow()) {
1936 const QXcbWindow *container =
static_cast<
const QXcbWindow *>(QPlatformWindow::parent());
1937 Q_ASSERT(container !=
nullptr);
1939 sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
1942 QPoint local(event_x, event_y);
1943 QPoint global(root_x, root_y);
1946 if (!connection()->isAtLeastXI21()) {
1949 angleDelta.setY(120);
1950 else if (detail == 5)
1951 angleDelta.setY(-120);
1952 else if (detail == 6)
1953 angleDelta.setX(120);
1954 else if (detail == 7)
1955 angleDelta.setX(-120);
1956 if (modifiers & Qt::AltModifier)
1957 angleDelta = angleDelta.transposed();
1958 QWindowSystemInterface::handleWheelEvent(window(), timestamp, local, global, QPoint(), angleDelta, modifiers);
1963 connection()->setMousePressWindow(
this);
1965 handleMouseEvent(timestamp, local, global, modifiers, type, source);
2123void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource source)
2125 QXcbConnection *conn = connection();
2126 auto *ev =
reinterpret_cast<xcb_input_button_press_event_t *>(event);
2128 if (ev->buttons_len > 0) {
2129 unsigned char *buttonMask = (
unsigned char *) &ev[1];
2135 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2136 qCDebug(lcQpaXInput,
"XI2 mouse event from touch device %d was ignored", ev->sourceid);
2139 for (
int i = 1; i <= 15; ++i)
2140 conn->setButtonState(conn->translateMouseButton(i),
qt_xcb_mask_is_set(buttonMask, i));
2143 const Qt::KeyboardModifiers modifiers = conn->keyboard()->translateModifiers(ev->mods.effective);
2144 const int event_x = fixed1616ToInt(ev->event_x);
2145 const int event_y = fixed1616ToInt(ev->event_y);
2146 const int root_x = fixed1616ToInt(ev->root_x);
2147 const int root_y = fixed1616ToInt(ev->root_y);
2149 conn->keyboard()->updateXKBStateFromXI(&ev->mods, &ev->group);
2151 const Qt::MouseButton button = conn->xiToQtMouseButton(ev->detail);
2153 const char *sourceName =
nullptr;
2154 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) {
2155 const QMetaObject *metaObject = qt_getEnumMetaObject(source);
2156 const QMetaEnum me = metaObject->enumerator(metaObject->indexOfEnumerator(qt_getEnumName(source)));
2157 sourceName = me.valueToKey(source);
2160 switch (ev->event_type) {
2161 case XCB_INPUT_BUTTON_PRESS:
2162 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2163 qCDebug(lcQpaXInputEvents,
"XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName);
2164 conn->setButtonState(button,
true);
2165 handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source);
2167 case XCB_INPUT_BUTTON_RELEASE:
2168 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2169 qCDebug(lcQpaXInputEvents,
"XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName);
2170 conn->setButtonState(button,
false);
2171 handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source);
2173 case XCB_INPUT_MOTION:
2174 if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled()))
2175 qCDebug(lcQpaXInputEvents,
"XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName);
2176 handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source);
2179 qWarning() <<
"Unrecognized XI2 mouse event" << ev->event_type;
2241void QXcbWindow::handlePropertyNotifyEvent(
const xcb_property_notify_event_t *event)
2243 connection()->setTime(event->time);
2245 const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
2247 if (event->atom == atom(QXcbAtom::Atom_NET_WM_STATE) || event->atom == atom(QXcbAtom::AtomWM_STATE)) {
2248 if (propertyDeleted)
2251 Qt::WindowStates newState = Qt::WindowNoState;
2253 if (event->atom == atom(QXcbAtom::AtomWM_STATE)) {
2254 auto reply =
Q_XCB_REPLY(xcb_get_property, xcb_connection(),
2255 0, m_window, atom(QXcbAtom::AtomWM_STATE),
2256 XCB_ATOM_ANY, 0, 1024);
2257 if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::AtomWM_STATE)) {
2258 const quint32 *data = (
const quint32 *)xcb_get_property_value(reply.get());
2259 if (reply->length != 0)
2260 m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC
2261 || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
2265 const NetWmStates states = netWmStates();
2270 if (m_minimized && (!connection()->wmSupport()->isSupportedByWM(NetWmStateHidden)
2271 || states.testFlag(NetWmStateHidden)))
2272 newState = Qt::WindowMinimized;
2274 if (states & NetWmStateFullScreen)
2275 newState |= Qt::WindowFullScreen;
2276 if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
2277 newState |= Qt::WindowMaximized;
2279 if (m_lastWindowStateEvent != newState) {
2280 QWindowSystemInterface::handleWindowStateChanged(window(), newState);
2281 m_lastWindowStateEvent = newState;
2282 m_windowState = newState;
2283 if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() ==
this)
2284 connection()->setMouseGrabber(
nullptr);
2287 }
else if (event->atom == atom(QXcbAtom::Atom_NET_FRAME_EXTENTS)) {
2288 m_dirtyFrameMargins =
true;