KWindowSystem

platforms/xcb/kwindowshadow.cpp
1 /*
2  SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "kwindowshadow_p_x11.h"
8 
9 #include <QX11Info>
10 
11 static const QByteArray s_atomName = QByteArrayLiteral("_KDE_NET_WM_SHADOW");
12 
13 bool 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(connection);
23  gc = xcb_generate_id(connection);
24 
25  xcb_create_pixmap(connection, depth, pixmap, rootWindow, width, height);
26  xcb_create_gc(connection, gc, pixmap, 0, nullptr);
27 
28  xcb_put_image(connection, //
29  XCB_IMAGE_FORMAT_Z_PIXMAP,
30  pixmap,
31  gc,
32  width,
33  height,
34  0,
35  0,
36  0,
37  depth,
38  image.sizeInBytes(),
39  image.constBits());
40 
41  return true;
42 }
43 
44 void KWindowShadowTilePrivateX11::destroy()
45 {
46  xcb_connection_t *connection = QX11Info::connection();
47  if (connection) {
48  xcb_free_pixmap(connection, pixmap);
49  xcb_free_gc(connection, gc);
50  }
51  pixmap = XCB_PIXMAP_NONE;
52  gc = XCB_NONE;
53 }
54 
55 KWindowShadowTilePrivateX11 *KWindowShadowTilePrivateX11::get(const KWindowShadowTile *tile)
56 {
57  KWindowShadowTilePrivate *d = KWindowShadowTilePrivate::get(tile);
58  return static_cast<KWindowShadowTilePrivateX11 *>(d);
59 }
60 
61 static 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(connection, //
69  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  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(connection, XCB_PROP_MODE_REPLACE, window->winId(), atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData());
179  xcb_flush(connection);
180 
181  return true;
182 }
183 
184 void 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(s_atomName);
199  if (atom == XCB_ATOM_NONE) {
200  return;
201  }
202 
203  xcb_delete_property(connection, window->winId(), atom);
204 }
205 
206 KWindowShadowTile::Ptr KWindowShadowPrivateX11::getOrCreateEmptyTile()
207 {
208  if (!emptyTile) {
209  QImage image(QSize(1, 1), QImage::Format_ARGB32);
210  image.fill(Qt::transparent);
211 
212  emptyTile = KWindowShadowTile::Ptr::create();
213  emptyTile->setImage(image);
214  emptyTile->create();
215  }
216 
217  return emptyTile;
218 }
QSharedPointer< T > create(Args &&...args)
KJOBWIDGETS_EXPORT QWidget * window(KJob *job)
T * data() const const
const char * constData() const const
WId winId() const const
virtual QPlatformSurface * surfaceHandle() const const =0
The KWindowShadowTile class provides a platform-indendent shadow tile representation.
Definition: kwindowshadow.h:23
transparent
int size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Oct 15 2021 22:41:50 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.