Changeset View
Changeset View
Standalone View
Standalone View
internal_client.cpp
- This file was added.
1 | /******************************************************************** | ||||
---|---|---|---|---|---|
2 | KWin - the KDE window manager | ||||
3 | This file is part of the KDE project. | ||||
4 | | ||||
5 | Copyright (C) 2019 Martin Flöser <mgraesslin@kde.org> | ||||
6 | | ||||
7 | This program is free software; you can redistribute it and/or modify | ||||
8 | it under the terms of the GNU General Public License as published by | ||||
9 | the Free Software Foundation; either version 2 of the License, or | ||||
10 | (at your option) any later version. | ||||
11 | | ||||
12 | This program is distributed in the hope that it will be useful, | ||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
15 | GNU General Public License for more details. | ||||
16 | | ||||
17 | You should have received a copy of the GNU General Public License | ||||
18 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||
19 | *********************************************************************/ | ||||
20 | #include "internal_client.h" | ||||
21 | #include "workspace.h" | ||||
22 | | ||||
23 | #include <KWayland/Client/surface.h> | ||||
24 | #include <KWayland/Server/surface_interface.h> | ||||
25 | | ||||
26 | #include <QOpenGLFramebufferObject> | ||||
27 | | ||||
28 | Q_DECLARE_METATYPE(NET::WindowType) | ||||
29 | | ||||
30 | static const QByteArray s_skipClosePropertyName = QByteArrayLiteral("KWIN_SKIP_CLOSE_ANIMATION"); | ||||
31 | | ||||
32 | namespace KWin | ||||
33 | { | ||||
34 | | ||||
35 | InternalClient::InternalClient(KWayland::Server::ShellSurfaceInterface *surface) | ||||
36 | : ShellClient(surface) | ||||
37 | { | ||||
38 | findInternalWindow(); | ||||
39 | updateInternalWindowGeometry(); | ||||
40 | updateDecoration(true); | ||||
41 | } | ||||
42 | | ||||
43 | InternalClient::InternalClient(KWayland::Server::XdgShellSurfaceInterface *surface) | ||||
44 | : ShellClient(surface) | ||||
45 | { | ||||
46 | } | ||||
47 | | ||||
48 | InternalClient::InternalClient(KWayland::Server::XdgShellPopupInterface *surface) | ||||
49 | : ShellClient(surface) | ||||
50 | { | ||||
51 | } | ||||
52 | | ||||
53 | InternalClient::~InternalClient() = default; | ||||
54 | | ||||
55 | void InternalClient::findInternalWindow() | ||||
56 | { | ||||
57 | const QWindowList windows = kwinApp()->topLevelWindows(); | ||||
58 | for (QWindow *w: windows) { | ||||
59 | auto s = KWayland::Client::Surface::fromWindow(w); | ||||
60 | if (!s) { | ||||
61 | continue; | ||||
62 | } | ||||
63 | if (s->id() != surface()->id()) { | ||||
64 | continue; | ||||
65 | } | ||||
66 | m_internalWindow = w; | ||||
67 | m_windowId = m_internalWindow->winId(); | ||||
68 | m_internalWindowFlags = m_internalWindow->flags(); | ||||
69 | connect(m_internalWindow, &QWindow::xChanged, this, &InternalClient::updateInternalWindowGeometry); | ||||
70 | connect(m_internalWindow, &QWindow::yChanged, this, &InternalClient::updateInternalWindowGeometry); | ||||
71 | connect(m_internalWindow, &QWindow::destroyed, this, [this] { m_internalWindow = nullptr; }); | ||||
72 | connect(m_internalWindow, &QWindow::opacityChanged, this, &InternalClient::setOpacity); | ||||
73 | | ||||
74 | const QVariant windowType = m_internalWindow->property("kwin_windowType"); | ||||
75 | if (!windowType.isNull()) { | ||||
76 | m_windowType = windowType.value<NET::WindowType>(); | ||||
77 | } | ||||
78 | setOpacity(m_internalWindow->opacity()); | ||||
79 | | ||||
80 | // skip close animation support | ||||
81 | setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool()); | ||||
82 | m_internalWindow->installEventFilter(this); | ||||
83 | return; | ||||
84 | } | ||||
85 | } | ||||
86 | | ||||
87 | bool InternalClient::eventFilter(QObject *watched, QEvent *event) | ||||
88 | { | ||||
89 | if (watched == m_internalWindow && event->type() == QEvent::DynamicPropertyChange) { | ||||
90 | QDynamicPropertyChangeEvent *pe = static_cast<QDynamicPropertyChangeEvent*>(event); | ||||
91 | if (pe->propertyName() == s_skipClosePropertyName) { | ||||
92 | setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool()); | ||||
93 | } | ||||
94 | if (pe->propertyName() == "kwin_windowType") { | ||||
95 | m_windowType = m_internalWindow->property("kwin_windowType").value<NET::WindowType>(); | ||||
96 | workspace()->updateClientArea(); | ||||
97 | } | ||||
98 | } | ||||
99 | return false; | ||||
100 | } | ||||
101 | | ||||
102 | NET::WindowType InternalClient::windowType(bool direct, int supported_types) const | ||||
103 | { | ||||
104 | Q_UNUSED(direct) | ||||
105 | Q_UNUSED(supported_types) | ||||
106 | return m_windowType; | ||||
107 | } | ||||
108 | | ||||
109 | void InternalClient::killWindow() | ||||
110 | { | ||||
111 | // we don't kill our internal windows | ||||
112 | } | ||||
113 | | ||||
114 | bool InternalClient::isPopupWindow() const | ||||
115 | { | ||||
116 | if (Toplevel::isPopupWindow()) { | ||||
117 | return true; | ||||
118 | } | ||||
119 | return m_internalWindowFlags.testFlag(Qt::Popup); | ||||
120 | } | ||||
121 | | ||||
122 | void InternalClient::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo) | ||||
123 | { | ||||
124 | if (fbo.isNull()) { | ||||
125 | unmap(); | ||||
126 | return; | ||||
127 | } | ||||
128 | | ||||
129 | setClientSize(fbo->size() / surface()->scale()); | ||||
130 | markAsMapped(); | ||||
131 | doSetGeometry(QRect(geom.topLeft(), clientSize())); | ||||
132 | Toplevel::setInternalFramebufferObject(fbo); | ||||
133 | Toplevel::addDamage(QRegion(0, 0, width(), height())); | ||||
134 | } | ||||
135 | | ||||
136 | void InternalClient::closeWindow() | ||||
137 | { | ||||
138 | if (m_internalWindow) { | ||||
139 | m_internalWindow->hide(); | ||||
140 | } | ||||
141 | } | ||||
142 | | ||||
143 | bool InternalClient::isCloseable() const | ||||
144 | { | ||||
145 | return true; | ||||
146 | } | ||||
147 | | ||||
148 | bool InternalClient::isMaximizable() const | ||||
149 | { | ||||
150 | return false; | ||||
151 | } | ||||
152 | | ||||
153 | bool InternalClient::isMinimizable() const | ||||
154 | { | ||||
155 | return false; | ||||
156 | } | ||||
157 | | ||||
158 | bool InternalClient::isMovable() const | ||||
159 | { | ||||
160 | return true; | ||||
161 | } | ||||
162 | | ||||
163 | bool InternalClient::isMovableAcrossScreens() const | ||||
164 | { | ||||
165 | return true; | ||||
166 | } | ||||
167 | | ||||
168 | bool InternalClient::isResizable() const | ||||
169 | { | ||||
170 | return true; | ||||
171 | } | ||||
172 | | ||||
173 | bool InternalClient::noBorder() const | ||||
174 | { | ||||
175 | return m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup); | ||||
176 | } | ||||
177 | | ||||
178 | bool InternalClient::userCanSetNoBorder() const | ||||
179 | { | ||||
180 | return !m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup); | ||||
181 | } | ||||
182 | | ||||
183 | bool InternalClient::wantsInput() const | ||||
184 | { | ||||
185 | return false; | ||||
186 | } | ||||
187 | | ||||
188 | bool InternalClient::acceptsFocus() const | ||||
189 | { | ||||
190 | return false; | ||||
191 | } | ||||
192 | | ||||
193 | bool InternalClient::isInternal() const | ||||
194 | { | ||||
195 | return true; | ||||
196 | } | ||||
197 | | ||||
198 | bool InternalClient::isLockScreen() const | ||||
199 | { | ||||
200 | if (m_internalWindow) { | ||||
201 | return m_internalWindow->property("org_kde_ksld_emergency").toBool(); | ||||
202 | } | ||||
203 | return false; | ||||
204 | } | ||||
205 | | ||||
206 | bool InternalClient::isInputMethod() const | ||||
207 | { | ||||
208 | if (m_internalWindow) { | ||||
209 | return m_internalWindow->property("__kwin_input_method").toBool(); | ||||
210 | } | ||||
211 | return false; | ||||
212 | } | ||||
213 | | ||||
214 | quint32 InternalClient::windowId() const | ||||
215 | { | ||||
216 | return m_windowId; | ||||
217 | } | ||||
218 | | ||||
219 | void InternalClient::updateInternalWindowGeometry() | ||||
220 | { | ||||
221 | if (!m_internalWindow) { | ||||
222 | return; | ||||
223 | } | ||||
224 | doSetGeometry(QRect(m_internalWindow->geometry().topLeft() - QPoint(borderLeft(), borderTop()), | ||||
225 | m_internalWindow->geometry().size() + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||||
226 | } | ||||
227 | | ||||
228 | bool InternalClient::requestGeometry(const QRect &rect) | ||||
229 | { | ||||
230 | if (!ShellClient::requestGeometry(rect)) { | ||||
231 | return false; | ||||
232 | } | ||||
233 | if (m_internalWindow) { | ||||
234 | m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||||
235 | } | ||||
236 | return true; | ||||
237 | } | ||||
238 | | ||||
239 | void InternalClient::doSetGeometry(const QRect &rect) | ||||
240 | { | ||||
241 | if (geom == rect && pendingGeometryUpdate() == PendingGeometryNone) { | ||||
242 | return; | ||||
243 | } | ||||
244 | if (!isUnmapped()) { | ||||
245 | addWorkspaceRepaint(visibleRect()); | ||||
246 | } | ||||
247 | geom = rect; | ||||
248 | | ||||
249 | if (isUnmapped() && geometryRestore().isEmpty() && !geom.isEmpty()) { | ||||
250 | // use first valid geometry as restore geometry | ||||
251 | setGeometryRestore(geom); | ||||
252 | } | ||||
253 | | ||||
254 | if (!isUnmapped()) { | ||||
255 | addWorkspaceRepaint(visibleRect()); | ||||
256 | } | ||||
257 | syncGeometryToInternalWindow(); | ||||
258 | if (hasStrut()) { | ||||
259 | workspace()->updateClientArea(); | ||||
260 | } | ||||
261 | const auto old = geometryBeforeUpdateBlocking(); | ||||
262 | updateGeometryBeforeUpdateBlocking(); | ||||
263 | emit geometryShapeChanged(this, old); | ||||
264 | | ||||
265 | if (isResize()) { | ||||
266 | performMoveResize(); | ||||
267 | } | ||||
268 | } | ||||
269 | | ||||
270 | void InternalClient::doMove(int x, int y) | ||||
271 | { | ||||
272 | Q_UNUSED(x) | ||||
273 | Q_UNUSED(y) | ||||
274 | syncGeometryToInternalWindow(); | ||||
275 | } | ||||
276 | | ||||
277 | void InternalClient::syncGeometryToInternalWindow() | ||||
278 | { | ||||
279 | if (!m_internalWindow) { | ||||
280 | return; | ||||
281 | } | ||||
282 | const QRect windowRect = QRect(geom.topLeft() + QPoint(borderLeft(), borderTop()), | ||||
283 | geom.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())); | ||||
284 | if (m_internalWindow->geometry() != windowRect) { | ||||
285 | // delay to end of cycle to prevent freeze, see BUG 384441 | ||||
286 | QTimer::singleShot(0, m_internalWindow, std::bind(static_cast<void (QWindow::*)(const QRect&)>(&QWindow::setGeometry), m_internalWindow, windowRect)); | ||||
287 | } | ||||
288 | } | ||||
289 | | ||||
290 | void InternalClient::resizeWithChecks(int w, int h, ForceGeometry_t force) | ||||
291 | { | ||||
292 | Q_UNUSED(force) | ||||
293 | if (!m_internalWindow) { | ||||
294 | return; | ||||
295 | } | ||||
296 | QRect area = workspace()->clientArea(WorkArea, this); | ||||
297 | // don't allow growing larger than workarea | ||||
298 | if (w > area.width()) { | ||||
299 | w = area.width(); | ||||
300 | } | ||||
301 | if (h > area.height()) { | ||||
302 | h = area.height(); | ||||
303 | } | ||||
304 | m_internalWindow->setGeometry(QRect(pos() + QPoint(borderLeft(), borderTop()), QSize(w, h) - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||||
305 | } | ||||
306 | | ||||
307 | void InternalClient::doResizeSync() | ||||
308 | { | ||||
309 | if (!m_internalWindow) { | ||||
310 | return; | ||||
311 | } | ||||
312 | const auto rect = moveResizeGeometry(); | ||||
313 | m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||||
314 | } | ||||
315 | | ||||
316 | QWindow *InternalClient::internalWindow() const | ||||
317 | { | ||||
318 | return m_internalWindow; | ||||
319 | } | ||||
320 | | ||||
321 | } |