1/*
2 SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "kwindowshadow_p_x11.h"
8
9#include <private/qtx11extras_p.h>
10
11static const QByteArray s_atomName = QByteArrayLiteral("_KDE_NET_WM_SHADOW");
12
13bool KWindowShadowTilePrivateX11::create()
14{
15 xcb_connection_t *connection = QX11Info::connection();
16 xcb_window_t rootWindow = QX11Info::appRootWindow();
17
18 const uint16_t width = uint16_t(image.width());
19 const uint16_t height = uint16_t(image.height());
20 const uint8_t depth = uint8_t(image.depth());
21
22 pixmap = xcb_generate_id(c: connection);
23 gc = xcb_generate_id(c: connection);
24
25 xcb_create_pixmap(c: connection, depth, pid: pixmap, drawable: rootWindow, width, height);
26 xcb_create_gc(c: connection, cid: gc, drawable: pixmap, value_mask: 0, value_list: nullptr);
27
28 xcb_put_image(c: connection, //
29 format: XCB_IMAGE_FORMAT_Z_PIXMAP,
30 drawable: pixmap,
31 gc,
32 width,
33 height,
34 dst_x: 0,
35 dst_y: 0,
36 left_pad: 0,
37 depth,
38 data_len: image.sizeInBytes(),
39 data: image.constBits());
40
41 return true;
42}
43
44void KWindowShadowTilePrivateX11::destroy()
45{
46 xcb_connection_t *connection = QX11Info::connection();
47 if (connection) {
48 xcb_free_pixmap(c: connection, pixmap);
49 xcb_free_gc(c: connection, gc);
50 }
51 pixmap = XCB_PIXMAP_NONE;
52 gc = XCB_NONE;
53}
54
55KWindowShadowTilePrivateX11 *KWindowShadowTilePrivateX11::get(const KWindowShadowTile *tile)
56{
57 KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile);
58 return static_cast<KWindowShadowTilePrivateX11 *>(d);
59}
60
61static xcb_atom_t lookupAtom(const QByteArray &atomName)
62{
63 xcb_connection_t *connection = QX11Info::connection();
64 if (!connection) {
65 return XCB_ATOM_NONE;
66 }
67
68 xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c: connection, //
69 only_if_exists: false,
70 name_len: atomName.size(),
71 name: atomName.constData());
72 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c: connection, cookie: atomCookie, e: nullptr);
73
74 if (!reply) {
75 return XCB_ATOM_NONE;
76 }
77
78 xcb_atom_t atom = reply->atom;
79 free(ptr: reply);
80
81 return atom;
82}
83
84static xcb_pixmap_t nativeHandleForTile(const KWindowShadowTile::Ptr &tile)
85{
86 const auto d = KWindowShadowTilePrivateX11::get(tile: tile.data());
87 return d->pixmap;
88}
89
90bool KWindowShadowPrivateX11::create()
91{
92 xcb_connection_t *connection = QX11Info::connection();
93
94 const xcb_atom_t atom = lookupAtom(atomName: s_atomName);
95 if (atom == XCB_ATOM_NONE) {
96 return false;
97 }
98
99 QList<quint32> data(12);
100 int i = 0;
101
102 // Unfortunately we cannot use handle of XCB_PIXMAP_NONE for missing shadow tiles because
103 // KWin expects **all** shadow tile handles to be valid. Maybe we could address this small
104 // inconvenience and then remove the empty tile stuff.
105
106 if (topTile) {
107 data[i++] = nativeHandleForTile(tile: topTile);
108 } else {
109 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
110 }
111
112 if (topRightTile) {
113 data[i++] = nativeHandleForTile(tile: topRightTile);
114 } else {
115 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
116 }
117
118 if (rightTile) {
119 data[i++] = nativeHandleForTile(tile: rightTile);
120 } else {
121 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
122 }
123
124 if (bottomRightTile) {
125 data[i++] = nativeHandleForTile(tile: bottomRightTile);
126 } else {
127 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
128 }
129
130 if (bottomTile) {
131 data[i++] = nativeHandleForTile(tile: bottomTile);
132 } else {
133 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
134 }
135
136 if (bottomLeftTile) {
137 data[i++] = nativeHandleForTile(tile: bottomLeftTile);
138 } else {
139 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
140 }
141
142 if (leftTile) {
143 data[i++] = nativeHandleForTile(tile: leftTile);
144 } else {
145 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
146 }
147
148 if (topLeftTile) {
149 data[i++] = nativeHandleForTile(tile: topLeftTile);
150 } else {
151 data[i++] = nativeHandleForTile(tile: getOrCreateEmptyTile());
152 }
153
154 if (topLeftTile || topTile || topRightTile) {
155 data[i++] = uint32_t(padding.top());
156 } else {
157 data[i++] = 1;
158 }
159
160 if (topRightTile || rightTile || bottomRightTile) {
161 data[i++] = uint32_t(padding.right());
162 } else {
163 data[i++] = 1;
164 }
165
166 if (bottomRightTile || bottomTile || bottomLeftTile) {
167 data[i++] = uint32_t(padding.bottom());
168 } else {
169 data[i++] = 1;
170 }
171
172 if (bottomLeftTile || leftTile || topLeftTile) {
173 data[i++] = uint32_t(padding.left());
174 } else {
175 data[i++] = 1;
176 }
177
178 xcb_change_property(c: connection, mode: XCB_PROP_MODE_REPLACE, window: window->winId(), property: atom, type: XCB_ATOM_CARDINAL, format: 32, data_len: data.size(), data: data.constData());
179 xcb_flush(c: connection);
180
181 return true;
182}
183
184void KWindowShadowPrivateX11::destroy()
185{
186 emptyTile = nullptr;
187
188 // For some reason, QWindow changes visibility of QSurface::surfaceHandle().
189 const QSurface *surface = window;
190
191 // Attempting to uninstall the shadow after the platform window had been destroyed.
192 if (!(surface && surface->surfaceHandle())) {
193 return;
194 }
195
196 xcb_connection_t *connection = QX11Info::connection();
197
198 const xcb_atom_t atom = lookupAtom(atomName: s_atomName);
199 if (atom == XCB_ATOM_NONE) {
200 return;
201 }
202
203 xcb_delete_property(c: connection, window: window->winId(), property: atom);
204}
205
206KWindowShadowTile::Ptr KWindowShadowPrivateX11::getOrCreateEmptyTile()
207{
208 if (!emptyTile) {
209 QImage image(QSize(1, 1), QImage::Format_ARGB32);
210 image.fill(color: Qt::transparent);
211
212 emptyTile = KWindowShadowTile::Ptr::create();
213 emptyTile->setImage(image);
214 emptyTile->create();
215 }
216
217 return emptyTile;
218}
219

source code of kwindowsystem/src/platforms/xcb/kwindowshadow.cpp