File indexing completed on 2024-11-10 04:56:36
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "x11_standalone_overlaywindow.h" 0011 0012 #include "compositor.h" 0013 #include "core/renderloop.h" 0014 #include "scene/workspacescene.h" 0015 #include "utils/xcbutils.h" 0016 #include "x11_standalone_backend.h" 0017 0018 #include <QList> 0019 0020 #include <xcb/composite.h> 0021 #include <xcb/shape.h> 0022 #if XCB_COMPOSITE_MAJOR_VERSION > 0 || XCB_COMPOSITE_MINOR_VERSION >= 3 0023 #define KWIN_HAVE_XCOMPOSITE_OVERLAY 0024 #endif 0025 0026 namespace KWin 0027 { 0028 OverlayWindowX11::OverlayWindowX11(X11StandaloneBackend *backend) 0029 : OverlayWindow() 0030 , X11EventFilter(QList<int>{XCB_EXPOSE, XCB_VISIBILITY_NOTIFY}) 0031 , m_visible(true) 0032 , m_shown(false) 0033 , m_backend(backend) 0034 , m_window(XCB_WINDOW_NONE) 0035 { 0036 } 0037 0038 OverlayWindowX11::~OverlayWindowX11() 0039 { 0040 } 0041 0042 bool OverlayWindowX11::create() 0043 { 0044 Q_ASSERT(m_window == XCB_WINDOW_NONE); 0045 if (!Xcb::Extensions::self()->isCompositeOverlayAvailable()) { 0046 return false; 0047 } 0048 if (!Xcb::Extensions::self()->isShapeInputAvailable()) { // needed in setupOverlay() 0049 return false; 0050 } 0051 #ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY 0052 Xcb::OverlayWindow overlay(rootWindow()); 0053 if (overlay.isNull()) { 0054 return false; 0055 } 0056 m_window = overlay->overlay_win; 0057 if (m_window == XCB_WINDOW_NONE) { 0058 return false; 0059 } 0060 return true; 0061 #else 0062 return false; 0063 #endif 0064 } 0065 0066 void OverlayWindowX11::setup(xcb_window_t window) 0067 { 0068 Q_ASSERT(m_window != XCB_WINDOW_NONE); 0069 Q_ASSERT(Xcb::Extensions::self()->isShapeInputAvailable()); 0070 setNoneBackgroundPixmap(m_window); 0071 if (m_size.isValid()) { 0072 setShape(QRect(0, 0, m_size.width(), m_size.height())); 0073 } 0074 if (window != XCB_WINDOW_NONE) { 0075 setNoneBackgroundPixmap(window); 0076 setupInputShape(window); 0077 } 0078 const uint32_t eventMask = XCB_EVENT_MASK_VISIBILITY_CHANGE; 0079 xcb_change_window_attributes(connection(), m_window, XCB_CW_EVENT_MASK, &eventMask); 0080 } 0081 0082 void OverlayWindowX11::setupInputShape(xcb_window_t window) 0083 { 0084 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, window, 0, 0, 0, nullptr); 0085 } 0086 0087 void OverlayWindowX11::setNoneBackgroundPixmap(xcb_window_t window) 0088 { 0089 const uint32_t mask = XCB_BACK_PIXMAP_NONE; 0090 xcb_change_window_attributes(connection(), window, XCB_CW_BACK_PIXMAP, &mask); 0091 } 0092 0093 void OverlayWindowX11::show() 0094 { 0095 Q_ASSERT(m_window != XCB_WINDOW_NONE); 0096 if (m_shown) { 0097 return; 0098 } 0099 xcb_map_subwindows(connection(), m_window); 0100 xcb_map_window(connection(), m_window); 0101 m_shown = true; 0102 } 0103 0104 void OverlayWindowX11::hide() 0105 { 0106 Q_ASSERT(m_window != XCB_WINDOW_NONE); 0107 xcb_unmap_window(connection(), m_window); 0108 m_shown = false; 0109 const QSize &s = m_size; 0110 setShape(QRect(0, 0, s.width(), s.height())); 0111 } 0112 0113 void OverlayWindowX11::setShape(const QRegion ®) 0114 { 0115 // Avoid setting the same shape again, it causes flicker (apparently it is not a no-op 0116 // and triggers something). 0117 if (reg == m_shape) { 0118 return; 0119 } 0120 const QList<xcb_rectangle_t> xrects = Xcb::regionToRects(reg); 0121 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, 0122 m_window, 0, 0, xrects.count(), xrects.data()); 0123 setupInputShape(m_window); 0124 m_shape = reg; 0125 } 0126 0127 void OverlayWindowX11::resize(const QSize &size) 0128 { 0129 m_size = size; 0130 if (m_window == XCB_WINDOW_NONE) { 0131 return; 0132 } 0133 const uint32_t geometry[2] = { 0134 static_cast<uint32_t>(size.width()), 0135 static_cast<uint32_t>(size.height())}; 0136 xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, geometry); 0137 setShape(QRegion(0, 0, size.width(), size.height())); 0138 } 0139 0140 bool OverlayWindowX11::isVisible() const 0141 { 0142 return m_visible; 0143 } 0144 0145 void OverlayWindowX11::setVisibility(bool visible) 0146 { 0147 m_visible = visible; 0148 } 0149 0150 void OverlayWindowX11::destroy() 0151 { 0152 if (m_window == XCB_WINDOW_NONE) { 0153 return; 0154 } 0155 // reset the overlay shape 0156 xcb_rectangle_t rec = {0, 0, static_cast<uint16_t>(m_size.width()), static_cast<uint16_t>(m_size.height())}; 0157 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec); 0158 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec); 0159 #ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY 0160 xcb_composite_release_overlay_window(connection(), m_window); 0161 #endif 0162 m_window = XCB_WINDOW_NONE; 0163 m_shown = false; 0164 } 0165 0166 xcb_window_t OverlayWindowX11::window() const 0167 { 0168 return m_window; 0169 } 0170 0171 bool OverlayWindowX11::event(xcb_generic_event_t *event) 0172 { 0173 const uint8_t eventType = event->response_type & ~0x80; 0174 if (eventType == XCB_EXPOSE) { 0175 const auto *expose = reinterpret_cast<xcb_expose_event_t *>(event); 0176 if (expose->window == rootWindow() // root window needs repainting 0177 || (m_window != XCB_WINDOW_NONE && expose->window == m_window)) { // overlay needs repainting 0178 Compositor::self()->scene()->addRepaint(expose->x, expose->y, expose->width, expose->height); 0179 } 0180 } else if (eventType == XCB_VISIBILITY_NOTIFY) { 0181 const auto *visibility = reinterpret_cast<xcb_visibility_notify_event_t *>(event); 0182 if (m_window != XCB_WINDOW_NONE && visibility->window == m_window) { 0183 bool was_visible = isVisible(); 0184 setVisibility((visibility->state != XCB_VISIBILITY_FULLY_OBSCURED)); 0185 auto compositor = Compositor::self(); 0186 if (!was_visible && m_visible) { 0187 // hack for #154825 0188 compositor->scene()->addRepaintFull(); 0189 QTimer::singleShot(2000, compositor, [compositor]() { 0190 if (compositor->compositing()) { 0191 compositor->scene()->addRepaintFull(); 0192 } 0193 }); 0194 } 0195 m_backend->renderLoop()->scheduleRepaint(); 0196 } 0197 } 0198 return false; 0199 } 0200 0201 } // namespace KWin