diff --git a/src/platforms/xcb/kwindowshadow.cpp b/src/platforms/xcb/kwindowshadow.cpp index b5f9890..599ae06 100644 --- a/src/platforms/xcb/kwindowshadow.cpp +++ b/src/platforms/xcb/kwindowshadow.cpp @@ -1,219 +1,219 @@ /* Copyright (C) 2019 Vlad Zahorodnii This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kwindowshadow_p_x11.h" #include static const QByteArray s_atomName = QByteArrayLiteral("_KDE_NET_WM_SHADOW"); bool KWindowShadowTilePrivateX11::create() { xcb_connection_t *connection = QX11Info::connection(); xcb_window_t rootWindow = QX11Info::appRootWindow(); const uint16_t width = uint16_t(image.width()); const uint16_t height = uint16_t(image.height()); const uint8_t depth = uint8_t(image.depth()); pixmap = xcb_generate_id(connection); gc = xcb_generate_id(connection); xcb_create_pixmap(connection, depth, pixmap, rootWindow, width, height); xcb_create_gc(connection, gc, pixmap, 0, nullptr); xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, gc, width, height, 0, 0, 0, depth, image.sizeInBytes(), image.constBits()); return true; } void KWindowShadowTilePrivateX11::destroy() { xcb_connection_t *connection = QX11Info::connection(); - - xcb_free_pixmap(connection, pixmap); - xcb_free_gc(connection, gc); - + if (connection) { + xcb_free_pixmap(connection, pixmap); + xcb_free_gc(connection, gc); + } pixmap = XCB_PIXMAP_NONE; gc = XCB_NONE; } KWindowShadowTilePrivateX11 *KWindowShadowTilePrivateX11::get(const KWindowShadowTile *tile) { KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile); return static_cast(d); } static xcb_atom_t lookupAtom(const QByteArray &atomName) { xcb_connection_t *connection = QX11Info::connection(); if (!connection) { return XCB_ATOM_NONE; } xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(connection, false, atomName.size(), atomName.constData()); xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, atomCookie, nullptr); if (!reply) { return XCB_ATOM_NONE; } xcb_atom_t atom = reply->atom; free(reply); return atom; } static xcb_pixmap_t nativeHandleForTile(const KWindowShadowTile::Ptr &tile) { const auto d = KWindowShadowTilePrivateX11::get(tile.data()); return d->pixmap; } bool KWindowShadowPrivateX11::create() { xcb_connection_t *connection = QX11Info::connection(); const xcb_atom_t atom = lookupAtom(s_atomName); if (atom == XCB_ATOM_NONE) { return false; } QVector data(12); int i = 0; // Unfortunately we cannot use handle of XCB_PIXMAP_NONE for missing shadow tiles because // KWin expects **all** shadow tile handles to be valid. Maybe we could address this small // inconvenience and then remove the empty tile stuff. if (topTile) { data[i++] = nativeHandleForTile(topTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (topRightTile) { data[i++] = nativeHandleForTile(topRightTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (rightTile) { data[i++] = nativeHandleForTile(rightTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (bottomRightTile) { data[i++] = nativeHandleForTile(bottomRightTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (bottomTile) { data[i++] = nativeHandleForTile(bottomTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (bottomLeftTile) { data[i++] = nativeHandleForTile(bottomLeftTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (leftTile) { data[i++] = nativeHandleForTile(leftTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (topLeftTile) { data[i++] = nativeHandleForTile(topLeftTile); } else { data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); } if (topLeftTile || topTile || topRightTile) { data[i++] = uint32_t(padding.top()); } else { data[i++] = 1; } if (topRightTile || rightTile || bottomRightTile) { data[i++] = uint32_t(padding.right()); } else { data[i++] = 1; } if (bottomRightTile || bottomTile || bottomLeftTile) { data[i++] = uint32_t(padding.bottom()); } else { data[i++] = 1; } if (bottomLeftTile || leftTile || topLeftTile) { data[i++] = uint32_t(padding.left()); } else { data[i++] = 1; } xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window->winId(), atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData()); xcb_flush(connection); return true; } void KWindowShadowPrivateX11::destroy() { emptyTile = nullptr; // For some reason, QWindow changes visibility of QSurface::surfaceHandle(). const QSurface *surface = window; // Attempting to uninstall the shadow after the platform window had been destroyed. if (!(surface && surface->surfaceHandle())) { return; } xcb_connection_t *connection = QX11Info::connection(); const xcb_atom_t atom = lookupAtom(s_atomName); if (atom == XCB_ATOM_NONE) { return; } xcb_delete_property(connection, window->winId(), atom); } KWindowShadowTile::Ptr KWindowShadowPrivateX11::getOrCreateEmptyTile() { if (!emptyTile) { QImage image(QSize(1, 1), QImage::Format_ARGB32); image.fill(Qt::transparent); emptyTile = KWindowShadowTile::Ptr::create(); emptyTile->setImage(image); emptyTile->create(); } return emptyTile; }