Changeset View
Changeset View
Standalone View
Standalone View
src/platforms/xcb/kwindowshadow.cpp
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | Copyright (C) 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org> | ||||
3 | | ||||
4 | This library is free software; you can redistribute it and/or | ||||
5 | modify it under the terms of the GNU Lesser General Public | ||||
6 | License as published by the Free Software Foundation; either | ||||
7 | version 2.1 of the License, or (at your option) any later version. | ||||
8 | | ||||
9 | This library is distributed in the hope that it will be useful, | ||||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
12 | Lesser General Public License for more details. | ||||
13 | | ||||
14 | You should have received a copy of the GNU Lesser General Public | ||||
15 | License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||||
16 | */ | ||||
17 | | ||||
18 | #include "kwindowshadow_p_x11.h" | ||||
19 | | ||||
20 | #include <QX11Info> | ||||
21 | | ||||
22 | static const QByteArray s_atomName = QByteArrayLiteral("_KDE_NET_WM_SHADOW"); | ||||
23 | | ||||
24 | bool KWindowShadowTilePrivateX11::create() | ||||
25 | { | ||||
26 | xcb_connection_t *connection = QX11Info::connection(); | ||||
27 | xcb_window_t rootWindow = QX11Info::appRootWindow(); | ||||
28 | | ||||
29 | const uint16_t width = uint16_t(image.width()); | ||||
30 | const uint16_t height = uint16_t(image.height()); | ||||
31 | const uint8_t depth = uint8_t(image.depth()); | ||||
32 | | ||||
33 | pixmap = xcb_generate_id(connection); | ||||
34 | gc = xcb_generate_id(connection); | ||||
35 | | ||||
36 | xcb_create_pixmap(connection, depth, pixmap, rootWindow, width, height); | ||||
37 | xcb_create_gc(connection, gc, pixmap, 0, nullptr); | ||||
38 | | ||||
39 | xcb_put_image(connection, XCB_IMAGE_FORMAT_Z_PIXMAP, pixmap, gc, width, height, | ||||
40 | 0, 0, 0, depth, image.sizeInBytes(), image.constBits()); | ||||
41 | | ||||
42 | return true; | ||||
43 | } | ||||
44 | | ||||
45 | void KWindowShadowTilePrivateX11::destroy() | ||||
46 | { | ||||
47 | xcb_connection_t *connection = QX11Info::connection(); | ||||
48 | | ||||
49 | xcb_free_pixmap(connection, pixmap); | ||||
50 | xcb_free_gc(connection, gc); | ||||
51 | | ||||
52 | pixmap = XCB_PIXMAP_NONE; | ||||
53 | gc = XCB_NONE; | ||||
54 | } | ||||
55 | | ||||
56 | KWindowShadowTilePrivateX11 *KWindowShadowTilePrivateX11::get(const KWindowShadowTile *tile) | ||||
57 | { | ||||
58 | KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile); | ||||
59 | return static_cast<KWindowShadowTilePrivateX11 *>(d); | ||||
60 | } | ||||
61 | | ||||
62 | static xcb_atom_t lookupAtom(const QByteArray &atomName) | ||||
63 | { | ||||
64 | xcb_connection_t *connection = QX11Info::connection(); | ||||
65 | if (!connection) { | ||||
66 | return XCB_ATOM_NONE; | ||||
67 | } | ||||
68 | | ||||
69 | xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(connection, false, | ||||
70 | atomName.size(), | ||||
71 | atomName.constData()); | ||||
72 | xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, atomCookie, nullptr); | ||||
73 | | ||||
74 | if (!reply) { | ||||
75 | return XCB_ATOM_NONE; | ||||
76 | } | ||||
77 | | ||||
78 | xcb_atom_t atom = reply->atom; | ||||
79 | free(reply); | ||||
80 | | ||||
81 | return atom; | ||||
82 | } | ||||
83 | | ||||
84 | static xcb_pixmap_t nativeHandleForTile(const KWindowShadowTile::Ptr &tile) | ||||
85 | { | ||||
86 | const auto d = KWindowShadowTilePrivateX11::get(tile.data()); | ||||
87 | return d->pixmap; | ||||
88 | } | ||||
89 | | ||||
90 | bool KWindowShadowPrivateX11::create() | ||||
91 | { | ||||
92 | xcb_connection_t *connection = QX11Info::connection(); | ||||
93 | | ||||
94 | const xcb_atom_t atom = lookupAtom(s_atomName); | ||||
95 | if (atom == XCB_ATOM_NONE) { | ||||
96 | return false; | ||||
97 | } | ||||
98 | | ||||
99 | QVector<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(topTile); | ||||
108 | } else { | ||||
109 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
110 | } | ||||
111 | | ||||
112 | if (topRightTile) { | ||||
113 | data[i++] = nativeHandleForTile(topRightTile); | ||||
114 | } else { | ||||
115 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
116 | } | ||||
117 | | ||||
118 | if (rightTile) { | ||||
119 | data[i++] = nativeHandleForTile(rightTile); | ||||
120 | } else { | ||||
121 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
122 | } | ||||
123 | | ||||
124 | if (bottomRightTile) { | ||||
125 | data[i++] = nativeHandleForTile(bottomRightTile); | ||||
126 | } else { | ||||
127 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
128 | } | ||||
129 | | ||||
130 | if (bottomTile) { | ||||
131 | data[i++] = nativeHandleForTile(bottomTile); | ||||
132 | } else { | ||||
133 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
134 | } | ||||
135 | | ||||
136 | if (bottomLeftTile) { | ||||
137 | data[i++] = nativeHandleForTile(bottomLeftTile); | ||||
138 | } else { | ||||
139 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
140 | } | ||||
141 | | ||||
142 | if (leftTile) { | ||||
143 | data[i++] = nativeHandleForTile(leftTile); | ||||
144 | } else { | ||||
145 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
146 | } | ||||
147 | | ||||
148 | if (topLeftTile) { | ||||
149 | data[i++] = nativeHandleForTile(topLeftTile); | ||||
150 | } else { | ||||
151 | data[i++] = nativeHandleForTile(getOrCreateEmptyTile()); | ||||
152 | } | ||||
153 | | ||||
154 | data[i++] = uint32_t(padding.top()); | ||||
155 | data[i++] = uint32_t(padding.right()); | ||||
156 | data[i++] = uint32_t(padding.bottom()); | ||||
157 | data[i++] = uint32_t(padding.left()); | ||||
158 | | ||||
159 | xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window->winId(), atom, | ||||
160 | XCB_ATOM_CARDINAL, 32, data.size(), data.constData()); | ||||
161 | xcb_flush(connection); | ||||
162 | | ||||
163 | return true; | ||||
164 | } | ||||
165 | | ||||
166 | void KWindowShadowPrivateX11::destroy() | ||||
167 | { | ||||
168 | emptyTile = nullptr; | ||||
169 | | ||||
170 | // For some reason, QWindow changes visibility of QSurface::surfaceHandle(). | ||||
171 | const QSurface *surface = window; | ||||
172 | | ||||
173 | // Attempting to uninstall the shadow after the platform window had been destroyed. | ||||
174 | if (!(surface && surface->surfaceHandle())) { | ||||
175 | return; | ||||
176 | } | ||||
177 | | ||||
178 | xcb_connection_t *connection = QX11Info::connection(); | ||||
179 | | ||||
180 | const xcb_atom_t atom = lookupAtom(s_atomName); | ||||
181 | if (atom == XCB_ATOM_NONE) { | ||||
182 | return; | ||||
183 | } | ||||
184 | | ||||
185 | xcb_delete_property(connection, window->winId(), atom); | ||||
186 | } | ||||
187 | | ||||
188 | KWindowShadowTile::Ptr KWindowShadowPrivateX11::getOrCreateEmptyTile() | ||||
189 | { | ||||
190 | if (!emptyTile) { | ||||
191 | QImage image(QSize(1, 1), QImage::Format_ARGB32); | ||||
192 | image.fill(Qt::transparent); | ||||
193 | | ||||
194 | emptyTile = KWindowShadowTile::Ptr::create(); | ||||
195 | emptyTile->setImage(image); | ||||
196 | emptyTile->create(); | ||||
197 | } | ||||
198 | | ||||
199 | return emptyTile; | ||||
200 | } |