Changeset View
Standalone View
shell_client.cpp
Show First 20 Lines • Show All 256 Lines • ▼ Show 20 Line(s) | 256 | connect(global, &XdgShellInterface::pingDelayed, | |||
---|---|---|---|---|---|
257 | this, [this](qint32 serial) { | 257 | this, [this](qint32 serial) { | ||
258 | auto it = m_pingSerials.find(serial); | 258 | auto it = m_pingSerials.find(serial); | ||
259 | if (it != m_pingSerials.end()) { | 259 | if (it != m_pingSerials.end()) { | ||
260 | qCDebug(KWIN_CORE) << "First ping timeout:" << caption(); | 260 | qCDebug(KWIN_CORE) << "First ping timeout:" << caption(); | ||
261 | setUnresponsive(true); | 261 | setUnresponsive(true); | ||
262 | } | 262 | } | ||
263 | }); | 263 | }); | ||
264 | 264 | | |||
265 | connect(m_xdgShellSurface, &XdgShellSurfaceInterface::configureAcknowledged, this, [this](int serial) { | ||||
266 | m_lastAckedConfigureRequest = serial; | ||||
267 | }); | ||||
268 | | ||||
265 | connect(global, &XdgShellInterface::pingTimeout, | 269 | connect(global, &XdgShellInterface::pingTimeout, | ||
266 | this, [this](qint32 serial) { | 270 | this, [this](qint32 serial) { | ||
267 | auto it = m_pingSerials.find(serial); | 271 | auto it = m_pingSerials.find(serial); | ||
268 | if (it != m_pingSerials.end()) { | 272 | if (it != m_pingSerials.end()) { | ||
269 | if (it.value() == PingReason::CloseWindow) { | 273 | if (it.value() == PingReason::CloseWindow) { | ||
270 | qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption(); | 274 | qCDebug(KWIN_CORE) << "Final ping timeout on a close attempt, asking to kill:" << caption(); | ||
271 | 275 | | |||
272 | //for internal windows, killing the window will delete this | 276 | //for internal windows, killing the window will delete this | ||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Line(s) | |||||
318 | } else if (m_xdgShellPopup) { | 322 | } else if (m_xdgShellPopup) { | ||
319 | connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, [this](SeatInterface *seat, quint32 serial) { | 323 | connect(m_xdgShellPopup, &XdgShellPopupInterface::grabRequested, this, [this](SeatInterface *seat, quint32 serial) { | ||
320 | Q_UNUSED(seat) | 324 | Q_UNUSED(seat) | ||
321 | Q_UNUSED(serial) | 325 | Q_UNUSED(serial) | ||
322 | //TODO - should check the parent had focus | 326 | //TODO - should check the parent had focus | ||
323 | m_hasPopupGrab = true; | 327 | m_hasPopupGrab = true; | ||
324 | }); | 328 | }); | ||
325 | 329 | | |||
330 | connect(m_xdgShellSurface, &XdgShellSurfaceInterface::configureAcknowledged, this, [this](int serial) { | ||||
331 | m_lastAckedConfigureRequest = serial; | ||||
332 | }); | ||||
333 | | ||||
326 | QRect position = QRect(m_xdgShellPopup->transientOffset(), m_xdgShellPopup->initialSize()); | 334 | QRect position = QRect(m_xdgShellPopup->transientOffset(), m_xdgShellPopup->initialSize()); | ||
327 | m_xdgShellPopup->configure(position); | 335 | m_xdgShellPopup->configure(position); | ||
328 | 336 | | |||
329 | connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); | 337 | connect(m_xdgShellPopup, &XdgShellPopupInterface::destroyed, this, &ShellClient::destroyClient); | ||
330 | } | 338 | } | ||
331 | 339 | | |||
332 | // set initial desktop | 340 | // set initial desktop | ||
333 | setDesktop(rules()->checkDesktop(m_internal ? int(NET::OnAllDesktops) : VirtualDesktopManager::self()->current(), true)); | 341 | setDesktop(rules()->checkDesktop(m_internal ? int(NET::OnAllDesktops) : VirtualDesktopManager::self()->current(), true)); | ||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Line(s) | 480 | { | |||
480 | emit opacityChanged(this, oldOpacity); | 488 | emit opacityChanged(this, oldOpacity); | ||
481 | } | 489 | } | ||
482 | 490 | | |||
483 | void ShellClient::addDamage(const QRegion &damage) | 491 | void ShellClient::addDamage(const QRegion &damage) | ||
484 | { | 492 | { | ||
485 | auto s = surface(); | 493 | auto s = surface(); | ||
486 | if (s->size().isValid()) { | 494 | if (s->size().isValid()) { | ||
487 | m_clientSize = s->size(); | 495 | m_clientSize = s->size(); | ||
488 | QPoint position = geom.topLeft(); | 496 | updatePendingGeometry(); | ||
489 | if (m_positionAfterResize.isValid()) { | | |||
490 | addLayerRepaint(geometry()); | | |||
491 | position = m_positionAfterResize.point(); | | |||
492 | m_positionAfterResize.clear(); | | |||
493 | } | | |||
494 | doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | | |||
495 | } | 497 | } | ||
496 | markAsMapped(); | 498 | markAsMapped(); | ||
497 | setDepth((s->buffer()->hasAlphaChannel() && !isDesktop()) ? 32 : 24); | 499 | setDepth((s->buffer()->hasAlphaChannel() && !isDesktop()) ? 32 : 24); | ||
498 | repaints_region += damage.translated(clientPos()); | 500 | repaints_region += damage.translated(clientPos()); | ||
499 | Toplevel::addDamage(damage); | 501 | Toplevel::addDamage(damage); | ||
500 | } | 502 | } | ||
501 | 503 | | |||
502 | void ShellClient::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo) | 504 | void ShellClient::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo) | ||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Line(s) | 597 | else | |||
596 | setPendingGeometryUpdate(PendingGeometryNormal); | 598 | setPendingGeometryUpdate(PendingGeometryNormal); | ||
597 | return; | 599 | return; | ||
598 | } | 600 | } | ||
599 | if (pendingGeometryUpdate() != PendingGeometryNone) { | 601 | if (pendingGeometryUpdate() != PendingGeometryNone) { | ||
600 | // reset geometry to the one before blocking, so that we can compare properly | 602 | // reset geometry to the one before blocking, so that we can compare properly | ||
601 | geom = geometryBeforeUpdateBlocking(); | 603 | geom = geometryBeforeUpdateBlocking(); | ||
602 | } | 604 | } | ||
603 | // TODO: better merge with Client's implementation | 605 | // TODO: better merge with Client's implementation | ||
604 | if (QSize(w, h) == geom.size() && !m_positionAfterResize.isValid()) { | 606 | if (QSize(w, h) == geom.size() && !isWaitingForMoveResizeSync()) { | ||
605 | // size didn't change, update directly | 607 | // size didn't change, update directly | ||
606 | doSetGeometry(QRect(x, y, w, h)); | 608 | doSetGeometry(QRect(x, y, w, h)); | ||
607 | } else { | 609 | } else { | ||
608 | // size did change, Client needs to provide a new buffer | 610 | // size did change, Client needs to provide a new buffer | ||
609 | requestGeometry(QRect(x, y, w, h)); | 611 | requestGeometry(QRect(x, y, w, h)); | ||
610 | } | 612 | } | ||
611 | } | 613 | } | ||
612 | 614 | | |||
▲ Show 20 Lines • Show All 552 Lines • ▼ Show 20 Line(s) | |||||
1165 | } | 1167 | } | ||
1166 | 1168 | | |||
1167 | void ShellClient::requestGeometry(const QRect &rect) | 1169 | void ShellClient::requestGeometry(const QRect &rect) | ||
1168 | { | 1170 | { | ||
1169 | if (m_requestGeometryBlockCounter != 0) { | 1171 | if (m_requestGeometryBlockCounter != 0) { | ||
1170 | m_blockedRequestGeometry = rect; | 1172 | m_blockedRequestGeometry = rect; | ||
1171 | return; | 1173 | return; | ||
1172 | } | 1174 | } | ||
1173 | m_positionAfterResize.setPoint(rect.topLeft()); | 1175 | PendingConfigureRequest configureRequest; | ||
1176 | configureRequest.positionAfterResize = rect.topLeft(); | ||||
1177 | | ||||
1174 | const QSize size = rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()); | 1178 | const QSize size = rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()); | ||
1175 | if (m_shellSurface) { | 1179 | if (m_shellSurface) { | ||
1176 | m_shellSurface->requestSize(size); | 1180 | m_shellSurface->requestSize(size); | ||
1177 | } | 1181 | } | ||
1178 | if (m_xdgShellSurface) { | 1182 | if (m_xdgShellSurface) { | ||
1179 | m_xdgShellSurface->configure(xdgSurfaceStates(), size); | 1183 | configureRequest.serialId = m_xdgShellSurface->configure(xdgSurfaceStates(), size); | ||
1180 | } | 1184 | } | ||
1181 | if (m_xdgShellPopup) { | 1185 | if (m_xdgShellPopup) { | ||
1182 | auto parent = transientFor(); | 1186 | auto parent = transientFor(); | ||
1183 | if (parent) { | 1187 | if (parent) { | ||
1184 | const QPoint globalClientContentPos = parent->geometry().topLeft() + parent->clientPos(); | 1188 | const QPoint globalClientContentPos = parent->geometry().topLeft() + parent->clientPos(); | ||
1185 | const QPoint relativeOffset = rect.topLeft() -globalClientContentPos; | 1189 | const QPoint relativeOffset = rect.topLeft() -globalClientContentPos; | ||
1186 | m_xdgShellPopup->configure(QRect(relativeOffset, rect.size())); | 1190 | configureRequest.serialId = m_xdgShellPopup->configure(QRect(relativeOffset, rect.size())); | ||
1187 | } | 1191 | } | ||
1188 | } | 1192 | } | ||
1189 | 1193 | | |||
1194 | m_pendingConfigureRequests.append(configureRequest); | ||||
1195 | | ||||
1190 | m_blockedRequestGeometry = QRect(); | 1196 | m_blockedRequestGeometry = QRect(); | ||
1191 | if (m_internal) { | 1197 | if (m_internal) { | ||
1192 | m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | 1198 | m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||
1193 | } | 1199 | } | ||
1194 | } | 1200 | } | ||
1195 | 1201 | | |||
1202 | void ShellClient::updatePendingGeometry() | ||||
1203 | { | ||||
1204 | QPoint position = geom.topLeft(); | ||||
1205 | const QPoint oldPosition = position; | ||||
1206 | while (! m_pendingConfigureRequests.isEmpty()) { | ||||
romangg: Instead of checking on every iteration, just check against the first element of the vector… | |||||
1207 | if (m_pendingConfigureRequests.first().serialId > m_lastAckedConfigureRequest) { | ||||
1208 | break; | ||||
1209 | } | ||||
1210 | auto configureRequest = m_pendingConfigureRequests.takeFirst(); | ||||
Instead of taking always the first one and by that looping through ignore (and remove) all configure events before the one associated with m_lastAckedConfigureRequest and only add a layer repaint and so on for m_lastAckedConfigureRequest. romangg: Instead of taking always the first one and by that looping through ignore (and remove) all… | |||||
Do you mean something like QPoint position = geom.topLeft(); it = m_pendingConfigureRequests.begin(); while (it != m_pendingConfigureRequests.end()) { if (it->serialId == m_lastAckedConfigureRequest) { if (position != it->positionAfterResize) { addLayerRepaint(geometry()); } position = it->positionAfterResize; m_pendingConfigureRequests.erase(m_pendingConfigureRequests.begin(), it); break; } it++; } doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); ? davidedmundson: Do you mean something like
```
QPoint position = geom.topLeft();
it =… | |||||
Yes. Use it++ in the erase statement to also erase the last acked one. Also there should still be an early loop exit in case the last acked configure request is lower and a cleanup in case the client does never send acks or acks without correct serials. Otherwise the vector can grow quickly. romangg: Yes. Use it++ in the erase statement to also erase the last acked one. Also there should still… | |||||
1211 | position = configureRequest.positionAfterResize; | ||||
1212 | } | ||||
1213 | if (position != oldPosition) { | ||||
1214 | addLayerRepaint(geometry()); | ||||
1215 | } | ||||
1216 | doSetGeometry(QRect(position, m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()))); | ||||
If several configure events have been sent the one last acked might not respond to the last configure event when updatePendingGeometry is called. Setting then the geometry with the current client size could still lead to not synchronized painting. romangg: If several configure events have been sent the one last acked might not respond to the last… | |||||
m_clientSize is the size of the last committed buffer (see ShellClient::addDamage). davidedmundson: >If several configure events have been sent the one last acked might not respond to the last… | |||||
1217 | } | ||||
1218 | | ||||
1196 | void ShellClient::clientFullScreenChanged(bool fullScreen) | 1219 | void ShellClient::clientFullScreenChanged(bool fullScreen) | ||
1197 | { | 1220 | { | ||
1198 | setFullScreen(fullScreen, false); | 1221 | setFullScreen(fullScreen, false); | ||
1199 | } | 1222 | } | ||
1200 | 1223 | | |||
1201 | void ShellClient::resizeWithChecks(int w, int h, ForceGeometry_t force) | 1224 | void ShellClient::resizeWithChecks(int w, int h, ForceGeometry_t force) | ||
1202 | { | 1225 | { | ||
1203 | Q_UNUSED(force) | 1226 | Q_UNUSED(force) | ||
▲ Show 20 Lines • Show All 320 Lines • ▼ Show 20 Line(s) | 1543 | { | |||
1524 | if (m_xdgShellPopup) { | 1547 | if (m_xdgShellPopup) { | ||
1525 | return m_xdgShellPopup->transientOffset(); | 1548 | return m_xdgShellPopup->transientOffset(); | ||
1526 | } | 1549 | } | ||
1527 | return QPoint(); | 1550 | return QPoint(); | ||
1528 | } | 1551 | } | ||
1529 | 1552 | | |||
1530 | bool ShellClient::isWaitingForMoveResizeSync() const | 1553 | bool ShellClient::isWaitingForMoveResizeSync() const | ||
1531 | { | 1554 | { | ||
1532 | return m_positionAfterResize.isValid(); | 1555 | return !m_pendingConfigureRequests.isEmpty(); | ||
1533 | } | 1556 | } | ||
1534 | 1557 | | |||
1535 | void ShellClient::doResizeSync() | 1558 | void ShellClient::doResizeSync() | ||
1536 | { | 1559 | { | ||
1537 | requestGeometry(moveResizeGeometry()); | 1560 | requestGeometry(moveResizeGeometry()); | ||
1538 | } | 1561 | } | ||
1539 | 1562 | | |||
1540 | QMatrix4x4 ShellClient::inputTransformation() const | 1563 | QMatrix4x4 ShellClient::inputTransformation() const | ||
▲ Show 20 Lines • Show All 173 Lines • Show Last 20 Lines |
Instead of checking on every iteration, just check against the first element of the vector before looping since the serials are monotonically increasing.