KWin
Loading...
Searching...
No Matches
surfaceitem_x11.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
8#include "compositor_x11.h"
10#include "x11syncmanager.h"
11#include "x11window.h"
12
13namespace KWin
14{
15
17 : SurfaceItem(scene, parent)
18 , m_window(window)
19{
21 this, &SurfaceItemX11::handleBufferGeometryChanged);
23 this, &SurfaceItemX11::handleShapeChanged);
24
25 m_damageHandle = xcb_generate_id(kwinApp()->x11Connection());
26 xcb_damage_create(kwinApp()->x11Connection(), m_damageHandle, window->frameId(),
27 XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
28
29 // With unmanaged windows there is a race condition between the client painting the window
30 // and us setting up damage tracking. If the client wins we won't get a damage event even
31 // though the window has been painted. To avoid this we mark the whole window as damaged
32 // immediately after creating the damage object.
33 if (window->isUnmanaged()) {
34 m_isDamaged = true;
35 }
36
38 setBufferSourceBox(QRectF(QPointF(0, 0), window->bufferGeometry().size()));
39 setBufferSize(window->bufferGeometry().size().toSize());
40}
41
46
48{
49 return m_window;
50}
51
53{
54 if (!damage().isEmpty()) {
55 X11Compositor *compositor = X11Compositor::self();
56 if (X11SyncManager *syncManager = compositor->syncManager()) {
57 syncManager->insertWait();
58 }
59 }
61}
62
64{
65 m_isDamaged = true;
67}
68
70{
71 if (!m_isDamaged) {
72 return false;
73 }
74
75 if (m_damageHandle == XCB_NONE) {
76 return true;
77 }
78
79 xcb_xfixes_region_t region = xcb_generate_id(kwinApp()->x11Connection());
80 xcb_xfixes_create_region(kwinApp()->x11Connection(), region, 0, nullptr);
81 xcb_damage_subtract(kwinApp()->x11Connection(), m_damageHandle, 0, region);
82
83 m_damageCookie = xcb_xfixes_fetch_region_unchecked(kwinApp()->x11Connection(), region);
84 xcb_xfixes_destroy_region(kwinApp()->x11Connection(), region);
85
86 m_havePendingDamageRegion = true;
87
88 return true;
89}
90
92{
93 if (!m_havePendingDamageRegion) {
94 return;
95 }
96 m_havePendingDamageRegion = false;
97
98 xcb_xfixes_fetch_region_reply_t *reply =
99 xcb_xfixes_fetch_region_reply(kwinApp()->x11Connection(), m_damageCookie, nullptr);
100 if (!reply) {
101 qCDebug(KWIN_CORE) << "Failed to check damage region";
102 return;
103 }
104
105 const int rectCount = xcb_xfixes_fetch_region_rectangles_length(reply);
106 QRegion region;
107
108 if (rectCount > 1 && rectCount < 16) {
109 xcb_rectangle_t *rects = xcb_xfixes_fetch_region_rectangles(reply);
110
111 QList<QRect> qtRects;
112 qtRects.reserve(rectCount);
113
114 for (int i = 0; i < rectCount; ++i) {
115 qtRects << QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height);
116 }
117 region.setRects(qtRects.constData(), rectCount);
118 } else {
119 region = QRect(reply->extents.x, reply->extents.y, reply->extents.width, reply->extents.height);
120 }
121 free(reply);
122
123 addDamage(region);
124 m_isDamaged = false;
125}
126
128{
129 // If the window is destroyed, we cannot destroy XDamage handle. :/
130 m_isDamaged = false;
131 m_damageHandle = XCB_NONE;
132}
133
135{
136 if (m_damageHandle != XCB_NONE) {
137 m_isDamaged = false;
138 xcb_damage_destroy(kwinApp()->x11Connection(), m_damageHandle);
139 m_damageHandle = XCB_NONE;
140 }
141}
142
143void SurfaceItemX11::handleBufferGeometryChanged()
144{
145 setDestinationSize(m_window->bufferGeometry().size());
146 setBufferSourceBox(QRectF(QPointF(0, 0), m_window->bufferGeometry().size()));
147 setBufferSize(m_window->bufferGeometry().size().toSize());
148}
149
150void SurfaceItemX11::handleShapeChanged()
151{
153 discardQuads();
154}
155
156QList<QRectF> SurfaceItemX11::shape() const
157{
158 const QRectF clipRect = m_window->clientGeometry().translated(-m_window->bufferGeometry().topLeft());
159 QList<QRectF> shape = m_window->shapeRegion();
160 // bounded to clipRect
161 for (QRectF &shapePart : shape) {
162 shapePart = shapePart.intersected(clipRect);
163 }
164 return shape;
165}
166
168{
169 QRegion shapeRegion;
170 for (const QRectF &shapePart : shape()) {
171 shapeRegion += shapePart.toRect();
172 }
173 if (!m_window->hasAlpha()) {
174 return shapeRegion;
175 } else {
176 return m_window->opaqueRegion() & shapeRegion;
177 }
178 return QRegion();
179}
180
181std::unique_ptr<SurfacePixmap> SurfaceItemX11::createPixmap()
182{
183 return std::make_unique<SurfacePixmapX11>(this);
184}
185
187 : SurfacePixmap(Compositor::self()->backend()->createSurfaceTextureX11(this), parent)
188 , m_item(item)
189{
190}
191
193{
194 if (m_pixmap != XCB_PIXMAP_NONE) {
195 xcb_free_pixmap(kwinApp()->x11Connection(), m_pixmap);
196 }
197}
198
200{
201 return m_pixmap != XCB_PIXMAP_NONE;
202}
203
204xcb_pixmap_t SurfacePixmapX11::pixmap() const
205{
206 return m_pixmap;
207}
208
209xcb_visualid_t SurfacePixmapX11::visual() const
210{
211 return m_item->window()->visual();
212}
213
215{
216 const X11Window *window = m_item->window();
217 if (window->isDeleted()) {
218 return;
219 }
220
221 XServerGrabber grabber;
222 xcb_connection_t *connection = kwinApp()->x11Connection();
223 xcb_window_t frame = window->frameId();
224 xcb_pixmap_t pixmap = xcb_generate_id(connection);
225 xcb_void_cookie_t namePixmapCookie = xcb_composite_name_window_pixmap_checked(connection,
226 frame,
227 pixmap);
228 Xcb::WindowAttributes windowAttributes(frame);
229 Xcb::WindowGeometry windowGeometry(frame);
230 if (xcb_generic_error_t *error = xcb_request_check(connection, namePixmapCookie)) {
231 qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (error code %d)",
232 window->window(), error->error_code);
233 free(error);
234 return;
235 }
236 // check that the received pixmap is valid and actually matches what we
237 // know about the window (i.e. size)
238 if (!windowAttributes || windowAttributes->map_state != XCB_MAP_STATE_VIEWABLE) {
239 qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x (not viewable)",
240 window->window());
241 xcb_free_pixmap(connection, pixmap);
242 return;
243 }
244 const QRectF bufferGeometry = window->bufferGeometry();
245 if (windowGeometry.size() != bufferGeometry.size()) {
246 qCDebug(KWIN_CORE, "Failed to create window pixmap for window 0x%x: window size (%fx%f) != buffer size (%fx%f)", window->window(),
247 windowGeometry.size().width(), windowGeometry.size().height(), bufferGeometry.width(), bufferGeometry.height());
248 xcb_free_pixmap(connection, pixmap);
249 return;
250 }
251
252 m_pixmap = pixmap;
253 m_hasAlphaChannel = window->hasAlpha();
254 // this class is only used on X11 where the logical size and
255 // device pixel size is guaranteed to be the same and we can convert safely
256 m_size = bufferGeometry.size().toSize();
257}
258
259} // namespace KWin
260
261#include "moc_surfaceitem_x11.cpp"
QRectF boundingRect() const
Definition item.cpp:157
void scheduleFrame()
Definition item.cpp:327
void discardQuads()
Definition item.cpp:350
void scheduleRepaint(const QRectF &region)
Definition item.cpp:396
void setDestinationSize(const QSizeF &size)
void preprocess() override
void setBufferSize(const QSize &size)
void addDamage(const QRegion &region)
QRegion damage() const
void setBufferSourceBox(const QRectF &box)
X11Window * window() const
QRegion opaque() const override
void preprocess() override
std::unique_ptr< SurfacePixmap > createPixmap() override
QList< QRectF > shape() const override
SurfaceItemX11(X11Window *window, Scene *scene, Item *parent=nullptr)
xcb_pixmap_t pixmap() const
bool isValid() const override
xcb_visualid_t visual() const
SurfacePixmapX11(SurfaceItemX11 *item, QObject *parent=nullptr)
QRectF bufferGeometry
Definition window.h:69
void bufferGeometryChanged(const QRectF &oldGeometry)
QRectF clientGeometry
Definition window.h:74
bool isDeleted() const
Definition window.cpp:540
static X11Compositor * self()
bool hasAlpha() const
Definition x11window.h:540
xcb_visualid_t visual() const
Definition x11window.h:530
xcb_window_t frameId() const
bool isUnmanaged() const override
xcb_window_t window() const
QList< QRectF > shapeRegion() const
QRegion opaqueRegion() const
Definition x11window.h:545
KWIN_EXPORT xcb_connection_t * connection()
Definition xcb.h:19