Changeset View
Changeset View
Standalone View
Standalone View
shell_client.cpp
1 | /******************************************************************** | 1 | /******************************************************************** | ||
---|---|---|---|---|---|
2 | KWin - the KDE window manager | 2 | KWin - the KDE window manager | ||
3 | This file is part of the KDE project. | 3 | This file is part of the KDE project. | ||
4 | 4 | | |||
5 | Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org> | 5 | Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org> | ||
6 | Copyright (C) 2018 David Edmundson <davidedmundson@kde.org> | 6 | Copyright (C) 2018 David Edmundson <davidedmundson@kde.org> | ||
7 | Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com> | ||||
7 | 8 | | |||
8 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | 11 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | 12 | (at your option) any later version. | ||
12 | 13 | | |||
13 | This program is distributed in the hope that it will be useful, | 14 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | |||||
66 | namespace KWin | 67 | namespace KWin | ||
67 | { | 68 | { | ||
68 | 69 | | |||
69 | ShellClient::ShellClient(ShellSurfaceInterface *surface) | 70 | ShellClient::ShellClient(ShellSurfaceInterface *surface) | ||
70 | : AbstractClient() | 71 | : AbstractClient() | ||
71 | , m_shellSurface(surface) | 72 | , m_shellSurface(surface) | ||
72 | , m_xdgShellSurface(nullptr) | 73 | , m_xdgShellSurface(nullptr) | ||
73 | , m_xdgShellPopup(nullptr) | 74 | , m_xdgShellPopup(nullptr) | ||
74 | , m_internal(surface->client() == waylandServer()->internalConnection()) | | |||
75 | { | 75 | { | ||
76 | setSurface(surface->surface()); | 76 | setSurface(surface->surface()); | ||
77 | init(); | 77 | init(); | ||
78 | m_isInitialized = true; | 78 | m_isInitialized = true; | ||
79 | } | 79 | } | ||
80 | 80 | | |||
81 | ShellClient::ShellClient(XdgShellSurfaceInterface *surface) | 81 | ShellClient::ShellClient(XdgShellSurfaceInterface *surface) | ||
82 | : AbstractClient() | 82 | : AbstractClient() | ||
83 | , m_shellSurface(nullptr) | 83 | , m_shellSurface(nullptr) | ||
84 | , m_xdgShellSurface(surface) | 84 | , m_xdgShellSurface(surface) | ||
85 | , m_xdgShellPopup(nullptr) | 85 | , m_xdgShellPopup(nullptr) | ||
86 | , m_internal(surface->client() == waylandServer()->internalConnection()) | | |||
87 | { | 86 | { | ||
88 | setSurface(surface->surface()); | 87 | setSurface(surface->surface()); | ||
89 | m_requestGeometryBlockCounter++; | 88 | m_requestGeometryBlockCounter++; | ||
90 | init(); | 89 | init(); | ||
91 | connect(surface->surface(), &SurfaceInterface::committed, this, &ShellClient::finishInit); | 90 | connect(surface->surface(), &SurfaceInterface::committed, this, &ShellClient::finishInit); | ||
92 | } | 91 | } | ||
93 | 92 | | |||
94 | ShellClient::ShellClient(XdgShellPopupInterface *surface) | 93 | ShellClient::ShellClient(XdgShellPopupInterface *surface) | ||
95 | : AbstractClient() | 94 | : AbstractClient() | ||
96 | , m_shellSurface(nullptr) | 95 | , m_shellSurface(nullptr) | ||
97 | , m_xdgShellSurface(nullptr) | 96 | , m_xdgShellSurface(nullptr) | ||
98 | , m_xdgShellPopup(surface) | 97 | , m_xdgShellPopup(surface) | ||
99 | , m_internal(surface->client() == waylandServer()->internalConnection()) | | |||
100 | { | 98 | { | ||
101 | setSurface(surface->surface()); | 99 | setSurface(surface->surface()); | ||
102 | m_requestGeometryBlockCounter++; | 100 | m_requestGeometryBlockCounter++; | ||
103 | init(); | 101 | init(); | ||
104 | connect(surface->surface(), &SurfaceInterface::committed, this, &ShellClient::finishInit); | 102 | connect(surface->surface(), &SurfaceInterface::committed, this, &ShellClient::finishInit); | ||
105 | } | 103 | } | ||
106 | 104 | | |||
107 | ShellClient::~ShellClient() = default; | 105 | ShellClient::~ShellClient() = default; | ||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Line(s) | 219 | if (s->buffer()) { | |||
223 | if (shouldExposeToWindowManagement()) { | 221 | if (shouldExposeToWindowManagement()) { | ||
224 | setupWindowManagementInterface(); | 222 | setupWindowManagementInterface(); | ||
225 | } | 223 | } | ||
226 | m_unmapped = false; | 224 | m_unmapped = false; | ||
227 | m_clientSize = s->size(); | 225 | m_clientSize = s->size(); | ||
228 | } else { | 226 | } else { | ||
229 | ready_for_painting = false; | 227 | ready_for_painting = false; | ||
230 | } | 228 | } | ||
231 | if (!m_internal) { | | |||
232 | doSetGeometry(QRect(QPoint(0, 0), m_clientSize)); | 229 | doSetGeometry(QRect(QPoint(0, 0), m_clientSize)); | ||
233 | } | | |||
234 | if (waylandServer()->inputMethodConnection() == s->client()) { | 230 | if (waylandServer()->inputMethodConnection() == s->client()) { | ||
235 | m_windowType = NET::OnScreenDisplay; | 231 | m_windowType = NET::OnScreenDisplay; | ||
236 | } | 232 | } | ||
237 | 233 | | |||
238 | connect(s, &SurfaceInterface::sizeChanged, this, | 234 | connect(s, &SurfaceInterface::sizeChanged, this, | ||
239 | [this] { | 235 | [this] { | ||
240 | m_clientSize = surface()->size(); | 236 | m_clientSize = surface()->size(); | ||
241 | doSetGeometry(QRect(pos(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | 237 | doSetGeometry(QRect(pos(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Line(s) | 320 | } else if (m_xdgShellPopup) { | |||
332 | connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, [this](int serial) { | 328 | connect(m_xdgShellPopup, &XdgShellPopupInterface::configureAcknowledged, this, [this](int serial) { | ||
333 | m_lastAckedConfigureRequest = serial; | 329 | m_lastAckedConfigureRequest = serial; | ||
334 | }); | 330 | }); | ||
335 | 331 | | |||
336 | connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); | 332 | connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); | ||
337 | } | 333 | } | ||
338 | 334 | | |||
339 | // set initial desktop | 335 | // set initial desktop | ||
340 | setDesktop(m_internal ? int(NET::OnAllDesktops) : VirtualDesktopManager::self()->current()); | 336 | setDesktop(VirtualDesktopManager::self()->current()); | ||
341 | 337 | | |||
342 | // setup shadow integration | 338 | // setup shadow integration | ||
343 | getShadow(); | 339 | getShadow(); | ||
344 | connect(s, &SurfaceInterface::shadowChanged, this, &Toplevel::getShadow); | 340 | connect(s, &SurfaceInterface::shadowChanged, this, &Toplevel::getShadow); | ||
345 | 341 | | |||
346 | connect(waylandServer(), &WaylandServer::foreignTransientChanged, this, [this](KWayland::Server::SurfaceInterface *child) { | 342 | connect(waylandServer(), &WaylandServer::foreignTransientChanged, this, [this](KWayland::Server::SurfaceInterface *child) { | ||
347 | if (child == surface()) { | 343 | if (child == surface()) { | ||
348 | setTransient(); | 344 | setTransient(); | ||
▲ Show 20 Lines • Show All 805 Lines • ▼ Show 20 Line(s) | 1149 | if (m_xdgShellSurface) { | |||
1154 | // TODO: proper | 1150 | // TODO: proper | ||
1155 | return true; | 1151 | return true; | ||
1156 | } | 1152 | } | ||
1157 | return false; | 1153 | return false; | ||
1158 | } | 1154 | } | ||
1159 | 1155 | | |||
1160 | void ShellClient::createWindowId() | 1156 | void ShellClient::createWindowId() | ||
1161 | { | 1157 | { | ||
1162 | if (!m_internal) { | | |||
1163 | m_windowId = waylandServer()->createWindowId(surface()); | 1158 | m_windowId = waylandServer()->createWindowId(surface()); | ||
1164 | } | 1159 | } | ||
1165 | } | | |||
1166 | 1160 | | |||
1167 | pid_t ShellClient::pid() const | 1161 | pid_t ShellClient::pid() const | ||
1168 | { | 1162 | { | ||
1169 | return surface()->client()->processId(); | 1163 | return surface()->client()->processId(); | ||
1170 | } | 1164 | } | ||
1171 | 1165 | | |||
1172 | bool ShellClient::isLockScreen() const | 1166 | bool ShellClient::isLockScreen() const | ||
1173 | { | 1167 | { | ||
1174 | return surface()->client() == waylandServer()->screenLockerClientConnection(); | 1168 | return surface()->client() == waylandServer()->screenLockerClientConnection(); | ||
1175 | } | 1169 | } | ||
1176 | 1170 | | |||
1177 | bool ShellClient::isInputMethod() const | 1171 | bool ShellClient::isInputMethod() const | ||
1178 | { | 1172 | { | ||
1179 | return surface()->client() == waylandServer()->inputMethodConnection(); | 1173 | return surface()->client() == waylandServer()->inputMethodConnection(); | ||
1180 | } | 1174 | } | ||
1181 | 1175 | | |||
1182 | bool ShellClient::requestGeometry(const QRect &rect) | 1176 | void ShellClient::requestGeometry(const QRect &rect) | ||
1183 | { | 1177 | { | ||
1184 | if (m_requestGeometryBlockCounter != 0) { | 1178 | if (m_requestGeometryBlockCounter != 0) { | ||
1185 | m_blockedRequestGeometry = rect; | 1179 | m_blockedRequestGeometry = rect; | ||
1186 | return false; | 1180 | return; | ||
1187 | } | 1181 | } | ||
1188 | 1182 | | |||
1189 | QSize size; | 1183 | QSize size; | ||
1190 | if (rect.isValid()) { | 1184 | if (rect.isValid()) { | ||
1191 | size = toWindowGeometry(rect.size()); | 1185 | size = toWindowGeometry(rect.size()); | ||
1192 | } else { | 1186 | } else { | ||
1193 | size = QSize(0, 0); | 1187 | size = QSize(0, 0); | ||
1194 | } | 1188 | } | ||
Show All 20 Lines | 1208 | if (rect.isValid()) { //if there's no requested size, then there's implicity no positional information worth using | |||
1215 | PendingConfigureRequest configureRequest; | 1209 | PendingConfigureRequest configureRequest; | ||
1216 | configureRequest.serialId = serialId; | 1210 | configureRequest.serialId = serialId; | ||
1217 | configureRequest.positionAfterResize = rect.topLeft(); | 1211 | configureRequest.positionAfterResize = rect.topLeft(); | ||
1218 | configureRequest.maximizeMode = m_requestedMaximizeMode; | 1212 | configureRequest.maximizeMode = m_requestedMaximizeMode; | ||
1219 | m_pendingConfigureRequests.append(configureRequest); | 1213 | m_pendingConfigureRequests.append(configureRequest); | ||
1220 | } | 1214 | } | ||
1221 | 1215 | | |||
1222 | m_blockedRequestGeometry = QRect(); | 1216 | m_blockedRequestGeometry = QRect(); | ||
1223 | return true; | | |||
1224 | } | 1217 | } | ||
1225 | 1218 | | |||
1226 | void ShellClient::updatePendingGeometry() | 1219 | void ShellClient::updatePendingGeometry() | ||
1227 | { | 1220 | { | ||
1228 | QPoint position = pos(); | 1221 | QPoint position = pos(); | ||
1229 | MaximizeMode maximizeMode = m_maximizeMode; | 1222 | MaximizeMode maximizeMode = m_maximizeMode; | ||
1230 | for (auto it = m_pendingConfigureRequests.begin(); it != m_pendingConfigureRequests.end(); it++) { | 1223 | for (auto it = m_pendingConfigureRequests.begin(); it != m_pendingConfigureRequests.end(); it++) { | ||
1231 | if (it->serialId > m_lastAckedConfigureRequest) { | 1224 | if (it->serialId > m_lastAckedConfigureRequest) { | ||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Line(s) | 1269 | { | |||
1287 | emit windowHidden(this); | 1280 | emit windowHidden(this); | ||
1288 | } | 1281 | } | ||
1289 | 1282 | | |||
1290 | void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface) | 1283 | void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface) | ||
1291 | { | 1284 | { | ||
1292 | m_plasmaShellSurface = surface; | 1285 | m_plasmaShellSurface = surface; | ||
1293 | auto updatePosition = [this, surface] { | 1286 | auto updatePosition = [this, surface] { | ||
1294 | QRect rect = QRect(surface->position(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())); | 1287 | QRect rect = QRect(surface->position(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())); | ||
1295 | // Shell surfaces of internal windows are sometimes desync to current value. | | |||
1296 | // Make sure to not set window geometry of internal windows to invalid values (bug 386304). | | |||
1297 | // This is a workaround. | | |||
1298 | if (!m_internal || rect.isValid()) { | | |||
1299 | doSetGeometry(rect); | 1288 | doSetGeometry(rect); | ||
1300 | } | | |||
1301 | }; | 1289 | }; | ||
1302 | auto updateRole = [this, surface] { | 1290 | auto updateRole = [this, surface] { | ||
1303 | NET::WindowType type = NET::Unknown; | 1291 | NET::WindowType type = NET::Unknown; | ||
1304 | switch (surface->role()) { | 1292 | switch (surface->role()) { | ||
1305 | case PlasmaShellSurfaceInterface::Role::Desktop: | 1293 | case PlasmaShellSurfaceInterface::Role::Desktop: | ||
1306 | type = NET::Desktop; | 1294 | type = NET::Desktop; | ||
1307 | break; | 1295 | break; | ||
1308 | case PlasmaShellSurfaceInterface::Role::Panel: | 1296 | case PlasmaShellSurfaceInterface::Role::Panel: | ||
▲ Show 20 Lines • Show All 510 Lines • ▼ Show 20 Line(s) | 1806 | connect(m_xdgDecoration, &XdgDecorationInterface::modeRequested, this, | |||
1819 | [this] () { | 1807 | [this] () { | ||
1820 | //force is true as we must send a new configure response | 1808 | //force is true as we must send a new configure response | ||
1821 | updateDecoration(false, true); | 1809 | updateDecoration(false, true); | ||
1822 | }); | 1810 | }); | ||
1823 | } | 1811 | } | ||
1824 | 1812 | | |||
1825 | bool ShellClient::shouldExposeToWindowManagement() | 1813 | bool ShellClient::shouldExposeToWindowManagement() | ||
1826 | { | 1814 | { | ||
1827 | if (m_internal) { | | |||
1828 | return false; | | |||
1829 | } | | |||
1830 | if (isLockScreen()) { | 1815 | if (isLockScreen()) { | ||
1831 | return false; | 1816 | return false; | ||
1832 | } | 1817 | } | ||
1833 | if (m_xdgShellPopup) { | 1818 | if (m_xdgShellPopup) { | ||
1834 | return false; | 1819 | return false; | ||
1835 | } | 1820 | } | ||
1836 | if (m_shellSurface) { | 1821 | if (m_shellSurface) { | ||
1837 | if (m_shellSurface->isTransient() && !m_shellSurface->acceptsKeyboardFocus()) { | 1822 | if (m_shellSurface->isTransient() && !m_shellSurface->acceptsKeyboardFocus()) { | ||
Show All 26 Lines | 1848 | { | |||
1864 | if (isMinimized()) { | 1849 | if (isMinimized()) { | ||
1865 | workspace()->clientHidden(this); | 1850 | workspace()->clientHidden(this); | ||
1866 | } else { | 1851 | } else { | ||
1867 | emit windowShown(this); | 1852 | emit windowShown(this); | ||
1868 | } | 1853 | } | ||
1869 | workspace()->updateMinimizedOfTransients(this); | 1854 | workspace()->updateMinimizedOfTransients(this); | ||
1870 | } | 1855 | } | ||
1871 | 1856 | | |||
1872 | bool ShellClient::setupCompositing() | | |||
1873 | { | | |||
1874 | if (m_compositingSetup) { | | |||
1875 | return true; | | |||
1876 | } | | |||
1877 | m_compositingSetup = Toplevel::setupCompositing(); | | |||
1878 | return m_compositingSetup; | | |||
1879 | } | | |||
1880 | | ||||
1881 | void ShellClient::finishCompositing(ReleaseReason releaseReason) | | |||
1882 | { | | |||
1883 | m_compositingSetup = false; | | |||
1884 | Toplevel::finishCompositing(releaseReason); | | |||
1885 | } | | |||
1886 | | ||||
1887 | void ShellClient::placeIn(const QRect &area) | 1857 | void ShellClient::placeIn(const QRect &area) | ||
1888 | { | 1858 | { | ||
1889 | Placement::self()->place(this, area); | 1859 | Placement::self()->place(this, area); | ||
1890 | setGeometryRestore(geometry()); | 1860 | setGeometryRestore(geometry()); | ||
1891 | } | 1861 | } | ||
1892 | 1862 | | |||
1893 | void ShellClient::showOnScreenEdge() | 1863 | void ShellClient::showOnScreenEdge() | ||
1894 | { | 1864 | { | ||
▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Line(s) | 1961 | if (m_shellSurface != nullptr) { | |||
1992 | return m_shellSurface->isPopup(); | 1962 | return m_shellSurface->isPopup(); | ||
1993 | } | 1963 | } | ||
1994 | if (m_xdgShellPopup != nullptr) { | 1964 | if (m_xdgShellPopup != nullptr) { | ||
1995 | return true; | 1965 | return true; | ||
1996 | } | 1966 | } | ||
1997 | return false; | 1967 | return false; | ||
1998 | } | 1968 | } | ||
1999 | 1969 | | |||
2000 | QWindow *ShellClient::internalWindow() const | | |||
2001 | { | | |||
2002 | return nullptr; | | |||
2003 | } | | |||
2004 | | ||||
2005 | bool ShellClient::supportsWindowRules() const | 1970 | bool ShellClient::supportsWindowRules() const | ||
2006 | { | 1971 | { | ||
2007 | if (m_plasmaShellSurface) { | 1972 | if (m_plasmaShellSurface) { | ||
2008 | return false; | 1973 | return false; | ||
2009 | } | 1974 | } | ||
2010 | return m_xdgShellSurface; | 1975 | return m_xdgShellSurface; | ||
2011 | } | 1976 | } | ||
2012 | 1977 | | |||
2013 | } | 1978 | } |