KWin
Loading...
Searching...
No Matches
x11_standalone_overlaywindow.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
11
12#include "compositor.h"
13#include "core/renderloop.h"
15#include "utils/xcbutils.h"
17
18#include <QList>
19
20#include <xcb/composite.h>
21#include <xcb/shape.h>
22#if XCB_COMPOSITE_MAJOR_VERSION > 0 || XCB_COMPOSITE_MINOR_VERSION >= 3
23#define KWIN_HAVE_XCOMPOSITE_OVERLAY
24#endif
25
26namespace KWin
27{
30 , X11EventFilter(QList<int>{XCB_EXPOSE, XCB_VISIBILITY_NOTIFY})
31 , m_visible(true)
32 , m_shown(false)
33 , m_backend(backend)
34 , m_window(XCB_WINDOW_NONE)
35{
36}
37
41
43{
44 Q_ASSERT(m_window == XCB_WINDOW_NONE);
45 if (!Xcb::Extensions::self()->isCompositeOverlayAvailable()) {
46 return false;
47 }
48 if (!Xcb::Extensions::self()->isShapeInputAvailable()) { // needed in setupOverlay()
49 return false;
50 }
51#ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY
52 Xcb::OverlayWindow overlay(rootWindow());
53 if (overlay.isNull()) {
54 return false;
55 }
56 m_window = overlay->overlay_win;
57 if (m_window == XCB_WINDOW_NONE) {
58 return false;
59 }
60 return true;
61#else
62 return false;
63#endif
64}
65
66void OverlayWindowX11::setup(xcb_window_t window)
67{
68 Q_ASSERT(m_window != XCB_WINDOW_NONE);
69 Q_ASSERT(Xcb::Extensions::self()->isShapeInputAvailable());
70 setNoneBackgroundPixmap(m_window);
71 if (m_size.isValid()) {
72 setShape(QRect(0, 0, m_size.width(), m_size.height()));
73 }
74 if (window != XCB_WINDOW_NONE) {
75 setNoneBackgroundPixmap(window);
76 setupInputShape(window);
77 }
78 const uint32_t eventMask = XCB_EVENT_MASK_VISIBILITY_CHANGE;
79 xcb_change_window_attributes(connection(), m_window, XCB_CW_EVENT_MASK, &eventMask);
80}
81
82void OverlayWindowX11::setupInputShape(xcb_window_t window)
83{
84 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, window, 0, 0, 0, nullptr);
85}
86
87void OverlayWindowX11::setNoneBackgroundPixmap(xcb_window_t window)
88{
89 const uint32_t mask = XCB_BACK_PIXMAP_NONE;
90 xcb_change_window_attributes(connection(), window, XCB_CW_BACK_PIXMAP, &mask);
91}
92
94{
95 Q_ASSERT(m_window != XCB_WINDOW_NONE);
96 if (m_shown) {
97 return;
98 }
99 xcb_map_subwindows(connection(), m_window);
100 xcb_map_window(connection(), m_window);
101 m_shown = true;
102}
103
105{
106 Q_ASSERT(m_window != XCB_WINDOW_NONE);
107 xcb_unmap_window(connection(), m_window);
108 m_shown = false;
109 const QSize &s = m_size;
110 setShape(QRect(0, 0, s.width(), s.height()));
111}
112
113void OverlayWindowX11::setShape(const QRegion &reg)
114{
115 // Avoid setting the same shape again, it causes flicker (apparently it is not a no-op
116 // and triggers something).
117 if (reg == m_shape) {
118 return;
119 }
120 const QList<xcb_rectangle_t> xrects = Xcb::regionToRects(reg);
121 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
122 m_window, 0, 0, xrects.count(), xrects.data());
123 setupInputShape(m_window);
124 m_shape = reg;
125}
126
127void OverlayWindowX11::resize(const QSize &size)
128{
129 m_size = size;
130 if (m_window == XCB_WINDOW_NONE) {
131 return;
132 }
133 const uint32_t geometry[2] = {
134 static_cast<uint32_t>(size.width()),
135 static_cast<uint32_t>(size.height())};
136 xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, geometry);
137 setShape(QRegion(0, 0, size.width(), size.height()));
138}
139
141{
142 return m_visible;
143}
144
146{
147 m_visible = visible;
148}
149
151{
152 if (m_window == XCB_WINDOW_NONE) {
153 return;
154 }
155 // reset the overlay shape
156 xcb_rectangle_t rec = {0, 0, static_cast<uint16_t>(m_size.width()), static_cast<uint16_t>(m_size.height())};
157 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec);
158 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec);
159#ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY
160 xcb_composite_release_overlay_window(connection(), m_window);
161#endif
162 m_window = XCB_WINDOW_NONE;
163 m_shown = false;
164}
165
166xcb_window_t OverlayWindowX11::window() const
167{
168 return m_window;
169}
170
171bool OverlayWindowX11::event(xcb_generic_event_t *event)
172{
173 const uint8_t eventType = event->response_type & ~0x80;
174 if (eventType == XCB_EXPOSE) {
175 const auto *expose = reinterpret_cast<xcb_expose_event_t *>(event);
176 if (expose->window == rootWindow() // root window needs repainting
177 || (m_window != XCB_WINDOW_NONE && expose->window == m_window)) { // overlay needs repainting
178 Compositor::self()->scene()->addRepaint(expose->x, expose->y, expose->width, expose->height);
179 }
180 } else if (eventType == XCB_VISIBILITY_NOTIFY) {
181 const auto *visibility = reinterpret_cast<xcb_visibility_notify_event_t *>(event);
182 if (m_window != XCB_WINDOW_NONE && visibility->window == m_window) {
183 bool was_visible = isVisible();
184 setVisibility((visibility->state != XCB_VISIBILITY_FULLY_OBSCURED));
185 auto compositor = Compositor::self();
186 if (!was_visible && m_visible) {
187 // hack for #154825
188 compositor->scene()->addRepaintFull();
189 QTimer::singleShot(2000, compositor, [compositor]() {
190 if (compositor->compositing()) {
191 compositor->scene()->addRepaintFull();
192 }
193 });
194 }
195 m_backend->renderLoop()->scheduleRepaint();
196 }
197 }
198 return false;
199}
200
201} // namespace KWin
WorkspaceScene * scene() const
Definition compositor.h:60
static Compositor * self()
bool event(xcb_generic_event_t *event) override
void destroy() override
Destroys XComposite overlay window.
xcb_window_t window() const override
void resize(const QSize &size) override
bool create() override
Creates XComposite overlay window, call initOverlay() and resize afterwards.
void setup(xcb_window_t window) override
Init overlay and the destination window in it.
OverlayWindowX11(X11StandaloneBackend *backend)
void setVisibility(bool visible) override
void scheduleRepaint(Item *item=nullptr)
void addRepaint(const QRegion &region)
Definition scene.cpp:91
static Extensions * self()
Definition xcbutils.cpp:346
KWIN_EXPORT xcb_window_t rootWindow()
Definition xcb.h:24
KWIN_EXPORT xcb_connection_t * connection()
Definition xcb.h:19