1/********************************************************************
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5Copyright (C) 2011 Arthur Arlt <a.arlt@stud.uni-heidelberg.de>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19*********************************************************************/
20
21#include "overlaywindow.h"
22
23#include "kwinglobals.h"
24#include "utils.h"
25#include "xcbutils.h"
26
27#include "assert.h"
28
29#include <QVector>
30
31#include <xcb/composite.h>
32#include <xcb/shape.h>
33#if XCB_COMPOSITE_MAJOR_VERSION > 0 || XCB_COMPOSITE_MINOR_VERSION >= 3
34#define KWIN_HAVE_XCOMPOSITE_OVERLAY
35#endif
36
37namespace KWin {
38OverlayWindow::OverlayWindow()
39 : m_visible(true)
40 , m_shown(false)
41 , m_window(XCB_WINDOW_NONE)
42{
43}
44
45OverlayWindow::~OverlayWindow()
46{
47}
48
49bool OverlayWindow::create()
50{
51 assert(m_window == XCB_WINDOW_NONE);
52 if (!Xcb::Extensions::self()->isCompositeOverlayAvailable())
53 return false;
54 if (!Xcb::Extensions::self()->isShapeInputAvailable()) // needed in setupOverlay()
55 return false;
56#ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY
57 Xcb::OverlayWindow overlay(rootWindow());
58 if (overlay.isNull()) {
59 return false;
60 }
61 m_window = overlay->overlay_win;
62 if (m_window == XCB_WINDOW_NONE)
63 return false;
64 resize(QSize(displayWidth(), displayHeight()));
65 return true;
66#else
67 return false;
68#endif
69}
70
71void OverlayWindow::setup(xcb_window_t window)
72{
73 assert(m_window != XCB_WINDOW_NONE);
74 assert(Xcb::Extensions::self()->isShapeInputAvailable());
75 setNoneBackgroundPixmap(m_window);
76 m_shape = QRegion();
77 setShape(QRect(0, 0, displayWidth(), displayHeight()));
78 if (window != XCB_WINDOW_NONE) {
79 setNoneBackgroundPixmap(window);
80 setupInputShape(window);
81 }
82 const uint32_t eventMask = XCB_EVENT_MASK_VISIBILITY_CHANGE;
83 xcb_change_window_attributes(connection(), m_window, XCB_CW_EVENT_MASK, &eventMask);
84}
85
86void OverlayWindow::setupInputShape(xcb_window_t window)
87{
88 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, window, 0, 0, 0, NULL);
89}
90
91void OverlayWindow::setNoneBackgroundPixmap(xcb_window_t window)
92{
93 const uint32_t mask = XCB_BACK_PIXMAP_NONE;
94 xcb_change_window_attributes(connection(), window, XCB_CW_BACK_PIXMAP, &mask);
95}
96
97void OverlayWindow::show()
98{
99 assert(m_window != XCB_WINDOW_NONE);
100 if (m_shown)
101 return;
102 xcb_map_subwindows(connection(), m_window);
103 xcb_map_window(connection(), m_window);
104 m_shown = true;
105}
106
107void OverlayWindow::hide()
108{
109 assert(m_window != XCB_WINDOW_NONE);
110 xcb_unmap_window(connection(), m_window);
111 m_shown = false;
112 setShape(QRect(0, 0, displayWidth(), displayHeight()));
113}
114
115void OverlayWindow::setShape(const QRegion& reg)
116{
117 // Avoid setting the same shape again, it causes flicker (apparently it is not a no-op
118 // and triggers something).
119 if (reg == m_shape)
120 return;
121 QVector< QRect > rects = reg.rects();
122 xcb_rectangle_t *xrects = new xcb_rectangle_t[rects.count()];
123 for (int i = 0;
124 i < rects.count();
125 ++i) {
126 xrects[ i ].x = rects[ i ].x();
127 xrects[ i ].y = rects[ i ].y();
128 xrects[ i ].width = rects[ i ].width();
129 xrects[ i ].height = rects[ i ].height();
130 }
131 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
132 m_window, 0, 0, rects.count(), xrects);
133 delete[] xrects;
134 setupInputShape(m_window);
135 m_shape = reg;
136}
137
138void OverlayWindow::resize(const QSize &size)
139{
140 assert(m_window != XCB_WINDOW_NONE);
141 const uint32_t geometry[2] = {
142 static_cast<uint32_t>(size.width()),
143 static_cast<uint32_t>(size.height())
144 };
145 xcb_configure_window(connection(), m_window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, geometry);
146 setShape(QRegion(0, 0, size.width(), size.height()));
147}
148
149bool OverlayWindow::isVisible() const
150{
151 return m_visible;
152}
153
154void OverlayWindow::setVisibility(bool visible)
155{
156 m_visible = visible;
157}
158
159void OverlayWindow::destroy()
160{
161 if (m_window == XCB_WINDOW_NONE)
162 return;
163 // reset the overlay shape
164 xcb_rectangle_t rec = { 0, 0, static_cast<uint16_t>(displayWidth()), static_cast<uint16_t>(displayHeight()) };
165 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec);
166 xcb_shape_rectangles(connection(), XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, m_window, 0, 0, 1, &rec);
167#ifdef KWIN_HAVE_XCOMPOSITE_OVERLAY
168 xcb_composite_release_overlay_window(connection(), m_window);
169#endif
170 m_window = XCB_WINDOW_NONE;
171 m_shown = false;
172}
173
174xcb_window_t OverlayWindow::window() const
175{
176 return m_window;
177}
178
179} // namespace KWin
180