File indexing completed on 2024-05-05 16:19:51
0001 /* 0002 SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "kwindowshadow_p_x11.h" 0008 0009 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 0010 #include <private/qtx11extras_p.h> 0011 #else 0012 #include <QX11Info> 0013 #endif 0014 0015 static const QByteArray s_atomName = QByteArrayLiteral("_KDE_NET_WM_SHADOW"); 0016 0017 bool KWindowShadowTilePrivateX11::create() 0018 { 0019 xcb_connection_t *connection = QX11Info::connection(); 0020 xcb_window_t rootWindow = QX11Info::appRootWindow(); 0021 0022 const uint16_t width = uint16_t(image.width()); 0023 const uint16_t height = uint16_t(image.height()); 0024 const uint8_t depth = uint8_t(image.depth()); 0025 0026 pixmap = xcb_generate_id(connection); 0027 gc = xcb_generate_id(connection); 0028 0029 xcb_create_pixmap(connection, depth, pixmap, rootWindow, width, height); 0030 xcb_create_gc(connection, gc, pixmap, 0, nullptr); 0031 0032 xcb_put_image(connection, // 0033 XCB_IMAGE_FORMAT_Z_PIXMAP, 0034 pixmap, 0035 gc, 0036 width, 0037 height, 0038 0, 0039 0, 0040 0, 0041 depth, 0042 image.sizeInBytes(), 0043 image.constBits()); 0044 0045 return true; 0046 } 0047 0048 void KWindowShadowTilePrivateX11::destroy() 0049 { 0050 xcb_connection_t *connection = QX11Info::connection(); 0051 if (connection) { 0052 xcb_free_pixmap(connection, pixmap); 0053 xcb_free_gc(connection, gc); 0054 } 0055 pixmap = XCB_PIXMAP_NONE; 0056 gc = XCB_NONE; 0057 } 0058 0059 KWindowShadowTilePrivateX11 *KWindowShadowTilePrivateX11::get(const KWindowShadowTile *tile) 0060 { 0061 KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile); 0062 return static_cast<KWindowShadowTilePrivateX11 *>(d); 0063 } 0064 0065 static xcb_atom_t lookupAtom(const QByteArray &atomName) 0066 { 0067 xcb_connection_t *connection = QX11Info::connection(); 0068 if (!connection) { 0069 return XCB_ATOM_NONE; 0070 } 0071 0072 xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(connection, // 0073 false, 0074 atomName.size(), 0075 atomName.constData()); 0076 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, atomCookie, nullptr); 0077 0078 if (!reply) { 0079 return XCB_ATOM_NONE; 0080 } 0081 0082 xcb_atom_t atom = reply->atom; 0083 free(reply); 0084 0085 return atom; 0086 } 0087 0088 static xcb_pixmap_t nativeHandleForTile(const KWindowShadowTile::Ptr &tile) 0089 { 0090 const auto d = KWindowShadowTilePrivateX11::get(tile.data()); 0091 return d->pixmap; 0092 } 0093 0094 bool KWindowShadowPrivateX11::create() 0095 { 0096 xcb_connection_t *connection = QX11Info::connection(); 0097 0098 const xcb_atom_t atom = lookupAtom(s_atomName); 0099 if (atom == XCB_ATOM_NONE) { 0100 return false; 0101 } 0102 0103 QVector<quint32> data(12); 0104 int i = 0; 0105 0106 // Unfortunately we cannot use handle of XCB_PIXMAP_NONE for missing shadow tiles because 0107 // KWin expects **all** shadow tile handles to be valid. Maybe we could address this small 0108 // inconvenience and then remove the empty tile stuff. 0109 0110 if (topTile) { 0111 data[i++] = nativeHandleForTile(topTile); 0112 } else { 0113 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0114 } 0115 0116 if (topRightTile) { 0117 data[i++] = nativeHandleForTile(topRightTile); 0118 } else { 0119 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0120 } 0121 0122 if (rightTile) { 0123 data[i++] = nativeHandleForTile(rightTile); 0124 } else { 0125 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0126 } 0127 0128 if (bottomRightTile) { 0129 data[i++] = nativeHandleForTile(bottomRightTile); 0130 } else { 0131 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0132 } 0133 0134 if (bottomTile) { 0135 data[i++] = nativeHandleForTile(bottomTile); 0136 } else { 0137 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0138 } 0139 0140 if (bottomLeftTile) { 0141 data[i++] = nativeHandleForTile(bottomLeftTile); 0142 } else { 0143 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0144 } 0145 0146 if (leftTile) { 0147 data[i++] = nativeHandleForTile(leftTile); 0148 } else { 0149 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0150 } 0151 0152 if (topLeftTile) { 0153 data[i++] = nativeHandleForTile(topLeftTile); 0154 } else { 0155 data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); 0156 } 0157 0158 if (topLeftTile || topTile || topRightTile) { 0159 data[i++] = uint32_t(padding.top()); 0160 } else { 0161 data[i++] = 1; 0162 } 0163 0164 if (topRightTile || rightTile || bottomRightTile) { 0165 data[i++] = uint32_t(padding.right()); 0166 } else { 0167 data[i++] = 1; 0168 } 0169 0170 if (bottomRightTile || bottomTile || bottomLeftTile) { 0171 data[i++] = uint32_t(padding.bottom()); 0172 } else { 0173 data[i++] = 1; 0174 } 0175 0176 if (bottomLeftTile || leftTile || topLeftTile) { 0177 data[i++] = uint32_t(padding.left()); 0178 } else { 0179 data[i++] = 1; 0180 } 0181 0182 xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window->winId(), atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData()); 0183 xcb_flush(connection); 0184 0185 return true; 0186 } 0187 0188 void KWindowShadowPrivateX11::destroy() 0189 { 0190 emptyTile = nullptr; 0191 0192 // For some reason, QWindow changes visibility of QSurface::surfaceHandle(). 0193 const QSurface *surface = window; 0194 0195 // Attempting to uninstall the shadow after the platform window had been destroyed. 0196 if (!(surface && surface->surfaceHandle())) { 0197 return; 0198 } 0199 0200 xcb_connection_t *connection = QX11Info::connection(); 0201 0202 const xcb_atom_t atom = lookupAtom(s_atomName); 0203 if (atom == XCB_ATOM_NONE) { 0204 return; 0205 } 0206 0207 xcb_delete_property(connection, window->winId(), atom); 0208 } 0209 0210 KWindowShadowTile::Ptr KWindowShadowPrivateX11::getOrCreateEmptyTile() 0211 { 0212 if (!emptyTile) { 0213 QImage image(QSize(1, 1), QImage::Format_ARGB32); 0214 image.fill(Qt::transparent); 0215 0216 emptyTile = KWindowShadowTile::Ptr::create(); 0217 emptyTile->setImage(image); 0218 emptyTile->create(); 0219 } 0220 0221 return emptyTile; 0222 }