Index: atoms.h =================================================================== --- atoms.h +++ atoms.h @@ -88,6 +88,7 @@ Xcb::Atom delete_atom; Xcb::Atom incr; Xcb::Atom wl_selection; + Xcb::Atom xwayland_randr_emu_monitor_rects; /** * @internal Index: atoms.cpp =================================================================== --- atoms.cpp +++ atoms.cpp @@ -81,6 +81,7 @@ , wl_selection(QByteArrayLiteral("WL_SELECTION")) , m_dtSmWindowInfo(QByteArrayLiteral("_DT_SM_WINDOW_INFO")) , m_motifSupport(QByteArrayLiteral("_MOTIF_WM_INFO")) + , xwayland_randr_emu_monitor_rects(QByteArrayLiteral("_XWAYLAND_RANDR_EMU_MONITOR_RECTS")) , m_helpersRetrieved(false) { } Index: geometry.cpp =================================================================== --- geometry.cpp +++ geometry.cpp @@ -27,6 +27,7 @@ */ +#include "atoms.h" #include "x11client.h" #include "composite.h" #include "cursor.h" @@ -1576,8 +1577,49 @@ c.window = window(); c.x = m_clientGeometry.x(); c.y = m_clientGeometry.y(); + + auto getEmulatedXWaylandSize = [this]() { + auto property = Xcb::Property(false, window(), + atoms->xwayland_randr_emu_monitor_rects, XCB_ATOM_CARDINAL, + 0, 1000); + if (!property) { + return QSize(); + } + uint32_t *rects = property.value(); + + if (property->value_len % 4) { + return QSize(); + } + + for (uint32_t i = 0; i < property->value_len / 4; i++) { + uint32_t *r = &rects[i]; + if (r[0] - m_clientGeometry.x() == 0 && r[1] - m_clientGeometry.y() == 0) { + return QSize(r[2], r[3]); + } + } + return QSize(); + }; + c.width = m_clientGeometry.width(); c.height = m_clientGeometry.height(); + + if (isFullScreen()) { + // Workaround for XWayland clients setting fullscreen + const QSize emulatedSize = getEmulatedXWaylandSize(); + if (emulatedSize.isValid()) { + c.width = emulatedSize.width(); + c.height = emulatedSize.height(); + const uint32_t values[] = { c.width, c.height }; + ScopedCPointer error(xcb_request_check(connection(), + xcb_configure_window_checked(connection(), c.window, + XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, + values))); + if (!error.isNull()) { + qCDebug(KWIN_CORE) << "Error on emulating XWayland size: " << error->error_code; + } + } + } + c.border_width = 0; c.above_sibling = XCB_WINDOW_NONE; c.override_redirect = 0; Index: scene.cpp =================================================================== --- scene.cpp +++ scene.cpp @@ -991,14 +991,21 @@ if (rect.isValid()) { sourceRect = QRectF(rect.topLeft() * textureScale, rect.bottomRight() * textureScale); - } else if (auto *buffer = surface->buffer()) { - // Try to get the source rectangle from the buffer size, what defines the source - // size without respect to destination size. - const auto origin = contentsRect.topLeft(); - const QRectF rect = QRectF(origin, buffer->size() - QSize(origin.x(), origin.y())); - // Make sure a buffer was set already. - if (rect.isValid()) { - sourceRect = rect; + } else { + auto *buffer = surface->buffer(); + // XWayland client's geometry must be taken from their content placement since the + // buffer size is not in sync. + if (buffer && !toplevel->isClient()) { + // Try to get the source rectangle from the buffer size, what defines the source + // size without respect to destination size. + const auto origin = contentsRect.topLeft(); + const QRectF rect = QRectF(origin, + buffer->size() - QSize(origin.x(), origin.y())); + Q_ASSERT(rect.isValid()); + // Make sure a buffer was set already. + if (rect.isValid()) { + sourceRect = rect; + } } } } Index: toplevel.h =================================================================== --- toplevel.h +++ toplevel.h @@ -713,6 +713,7 @@ bool m_isDamaged; private: + void handleXwaylandSurfaceSizeChange(); // when adding new data members, check also copyToDeleted() QUuid m_internalId; Xcb::Window m_client; Index: toplevel.cpp =================================================================== --- toplevel.cpp +++ toplevel.cpp @@ -713,11 +713,13 @@ using namespace KWayland::Server; if (m_surface) { disconnect(m_surface, &SurfaceInterface::damaged, this, &Toplevel::addDamage); - disconnect(m_surface, &SurfaceInterface::sizeChanged, this, &Toplevel::discardWindowPixmap); + disconnect(m_surface, &SurfaceInterface::sizeChanged, + this, &Toplevel::handleXwaylandSurfaceSizeChange); } m_surface = surface; connect(m_surface, &SurfaceInterface::damaged, this, &Toplevel::addDamage); - connect(m_surface, &SurfaceInterface::sizeChanged, this, &Toplevel::discardWindowPixmap); + connect(m_surface, &SurfaceInterface::sizeChanged, + this, &Toplevel::handleXwaylandSurfaceSizeChange); connect(m_surface, &SurfaceInterface::subSurfaceTreeChanged, this, [this] { // TODO improve to only update actual visual area @@ -735,6 +737,12 @@ emit surfaceChanged(); } +void Toplevel::handleXwaylandSurfaceSizeChange() +{ + discardWindowPixmap(); + Q_EMIT geometryShapeChanged(this, frameGeometry()); +} + void Toplevel::addDamage(const QRegion &damage) { m_isDamaged = true;