Split out a dedicated InternalClient class
Summary: Most of the functionality which is special to internal clients is moved from ShellClient to InternalClient. As KWin's qpa is still bound to the Wayland protocol InternalClient inherits from ShellClient. Due to that some aspects in ShellClient are "weird". ShellClient still detects whether it's an internal client and uses the variable m_internal to capture the state. This is required as we cannot use the isInternal method. Most of m_internal usage is in init which is called from constructor of ShellClient. Thus it's not possible to call into virtual methods of InternalClient. Also some of the code is duplicated and some methods are temporarily marked as virtual. The next step will be to remove ShmBuffer for internal windows which should decouple the two implementations further with the long term goal of having InternalClient inherit AbstractClient directly. Test Plan: Run nested KWin, triggered outline (OpenGL case) and debug console (shm case). InternalWindow unit test still passes. Reviewers: #kwin Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D18569
This commit is contained in:
parent
66faa480d4
commit
9b922f8833
7 changed files with 441 additions and 168 deletions
|
@ -493,6 +493,7 @@ set(kwin_KDEINIT_SRCS
|
|||
libinput/libinput_logging.cpp
|
||||
udev.cpp
|
||||
touch_hide_cursor_spy.cpp
|
||||
internal_client.cpp
|
||||
xwl/xwayland_interface.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "platform.h"
|
||||
#include "cursor.h"
|
||||
#include "effects.h"
|
||||
#include "internal_client.h"
|
||||
#include "shell_client.h"
|
||||
#include "screens.h"
|
||||
#include "wayland_server.h"
|
||||
|
@ -227,6 +228,7 @@ void InternalWindowTest::testEnterLeave()
|
|||
QVERIFY(!workspace()->activeClient());
|
||||
ShellClient *c = clientAddedSpy.first().first().value<ShellClient*>();
|
||||
QVERIFY(c->isInternal());
|
||||
QVERIFY(qobject_cast<InternalClient*>(c));
|
||||
QCOMPARE(c->icon().name(), QStringLiteral("wayland"));
|
||||
QVERIFY(!c->isDecorated());
|
||||
QCOMPARE(workspace()->findToplevel(&win), c);
|
||||
|
|
321
internal_client.cpp
Normal file
321
internal_client.cpp
Normal file
|
@ -0,0 +1,321 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2019 Martin Flöser <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "internal_client.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <KWayland/Client/surface.h>
|
||||
#include <KWayland/Server/surface_interface.h>
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
||||
Q_DECLARE_METATYPE(NET::WindowType)
|
||||
|
||||
static const QByteArray s_skipClosePropertyName = QByteArrayLiteral("KWIN_SKIP_CLOSE_ANIMATION");
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
InternalClient::InternalClient(KWayland::Server::ShellSurfaceInterface *surface)
|
||||
: ShellClient(surface)
|
||||
{
|
||||
findInternalWindow();
|
||||
updateInternalWindowGeometry();
|
||||
updateDecoration(true);
|
||||
}
|
||||
|
||||
InternalClient::InternalClient(KWayland::Server::XdgShellSurfaceInterface *surface)
|
||||
: ShellClient(surface)
|
||||
{
|
||||
}
|
||||
|
||||
InternalClient::InternalClient(KWayland::Server::XdgShellPopupInterface *surface)
|
||||
: ShellClient(surface)
|
||||
{
|
||||
}
|
||||
|
||||
InternalClient::~InternalClient() = default;
|
||||
|
||||
void InternalClient::findInternalWindow()
|
||||
{
|
||||
const QWindowList windows = kwinApp()->topLevelWindows();
|
||||
for (QWindow *w: windows) {
|
||||
auto s = KWayland::Client::Surface::fromWindow(w);
|
||||
if (!s) {
|
||||
continue;
|
||||
}
|
||||
if (s->id() != surface()->id()) {
|
||||
continue;
|
||||
}
|
||||
m_internalWindow = w;
|
||||
m_windowId = m_internalWindow->winId();
|
||||
m_internalWindowFlags = m_internalWindow->flags();
|
||||
connect(m_internalWindow, &QWindow::xChanged, this, &InternalClient::updateInternalWindowGeometry);
|
||||
connect(m_internalWindow, &QWindow::yChanged, this, &InternalClient::updateInternalWindowGeometry);
|
||||
connect(m_internalWindow, &QWindow::destroyed, this, [this] { m_internalWindow = nullptr; });
|
||||
connect(m_internalWindow, &QWindow::opacityChanged, this, &InternalClient::setOpacity);
|
||||
|
||||
const QVariant windowType = m_internalWindow->property("kwin_windowType");
|
||||
if (!windowType.isNull()) {
|
||||
m_windowType = windowType.value<NET::WindowType>();
|
||||
}
|
||||
setOpacity(m_internalWindow->opacity());
|
||||
|
||||
// skip close animation support
|
||||
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
|
||||
m_internalWindow->installEventFilter(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool InternalClient::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == m_internalWindow && event->type() == QEvent::DynamicPropertyChange) {
|
||||
QDynamicPropertyChangeEvent *pe = static_cast<QDynamicPropertyChangeEvent*>(event);
|
||||
if (pe->propertyName() == s_skipClosePropertyName) {
|
||||
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
|
||||
}
|
||||
if (pe->propertyName() == "kwin_windowType") {
|
||||
m_windowType = m_internalWindow->property("kwin_windowType").value<NET::WindowType>();
|
||||
workspace()->updateClientArea();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NET::WindowType InternalClient::windowType(bool direct, int supported_types) const
|
||||
{
|
||||
Q_UNUSED(direct)
|
||||
Q_UNUSED(supported_types)
|
||||
return m_windowType;
|
||||
}
|
||||
|
||||
void InternalClient::killWindow()
|
||||
{
|
||||
// we don't kill our internal windows
|
||||
}
|
||||
|
||||
bool InternalClient::isPopupWindow() const
|
||||
{
|
||||
if (Toplevel::isPopupWindow()) {
|
||||
return true;
|
||||
}
|
||||
return m_internalWindowFlags.testFlag(Qt::Popup);
|
||||
}
|
||||
|
||||
void InternalClient::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo)
|
||||
{
|
||||
if (fbo.isNull()) {
|
||||
unmap();
|
||||
return;
|
||||
}
|
||||
|
||||
setClientSize(fbo->size() / surface()->scale());
|
||||
markAsMapped();
|
||||
doSetGeometry(QRect(geom.topLeft(), clientSize()));
|
||||
Toplevel::setInternalFramebufferObject(fbo);
|
||||
Toplevel::addDamage(QRegion(0, 0, width(), height()));
|
||||
}
|
||||
|
||||
void InternalClient::closeWindow()
|
||||
{
|
||||
if (m_internalWindow) {
|
||||
m_internalWindow->hide();
|
||||
}
|
||||
}
|
||||
|
||||
bool InternalClient::isCloseable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalClient::isMaximizable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InternalClient::isMinimizable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InternalClient::isMovable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalClient::isMovableAcrossScreens() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalClient::isResizable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalClient::noBorder() const
|
||||
{
|
||||
return m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup);
|
||||
}
|
||||
|
||||
bool InternalClient::userCanSetNoBorder() const
|
||||
{
|
||||
return !m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup);
|
||||
}
|
||||
|
||||
bool InternalClient::wantsInput() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InternalClient::acceptsFocus() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InternalClient::isInternal() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InternalClient::isLockScreen() const
|
||||
{
|
||||
if (m_internalWindow) {
|
||||
return m_internalWindow->property("org_kde_ksld_emergency").toBool();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InternalClient::isInputMethod() const
|
||||
{
|
||||
if (m_internalWindow) {
|
||||
return m_internalWindow->property("__kwin_input_method").toBool();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
quint32 InternalClient::windowId() const
|
||||
{
|
||||
return m_windowId;
|
||||
}
|
||||
|
||||
void InternalClient::updateInternalWindowGeometry()
|
||||
{
|
||||
if (!m_internalWindow) {
|
||||
return;
|
||||
}
|
||||
doSetGeometry(QRect(m_internalWindow->geometry().topLeft() - QPoint(borderLeft(), borderTop()),
|
||||
m_internalWindow->geometry().size() + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
|
||||
bool InternalClient::requestGeometry(const QRect &rect)
|
||||
{
|
||||
if (!ShellClient::requestGeometry(rect)) {
|
||||
return false;
|
||||
}
|
||||
if (m_internalWindow) {
|
||||
m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void InternalClient::doSetGeometry(const QRect &rect)
|
||||
{
|
||||
if (geom == rect && pendingGeometryUpdate() == PendingGeometryNone) {
|
||||
return;
|
||||
}
|
||||
if (!isUnmapped()) {
|
||||
addWorkspaceRepaint(visibleRect());
|
||||
}
|
||||
geom = rect;
|
||||
|
||||
if (isUnmapped() && geometryRestore().isEmpty() && !geom.isEmpty()) {
|
||||
// use first valid geometry as restore geometry
|
||||
setGeometryRestore(geom);
|
||||
}
|
||||
|
||||
if (!isUnmapped()) {
|
||||
addWorkspaceRepaint(visibleRect());
|
||||
}
|
||||
syncGeometryToInternalWindow();
|
||||
if (hasStrut()) {
|
||||
workspace()->updateClientArea();
|
||||
}
|
||||
const auto old = geometryBeforeUpdateBlocking();
|
||||
updateGeometryBeforeUpdateBlocking();
|
||||
emit geometryShapeChanged(this, old);
|
||||
|
||||
if (isResize()) {
|
||||
performMoveResize();
|
||||
}
|
||||
}
|
||||
|
||||
void InternalClient::doMove(int x, int y)
|
||||
{
|
||||
Q_UNUSED(x)
|
||||
Q_UNUSED(y)
|
||||
syncGeometryToInternalWindow();
|
||||
}
|
||||
|
||||
void InternalClient::syncGeometryToInternalWindow()
|
||||
{
|
||||
if (!m_internalWindow) {
|
||||
return;
|
||||
}
|
||||
const QRect windowRect = QRect(geom.topLeft() + QPoint(borderLeft(), borderTop()),
|
||||
geom.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
|
||||
if (m_internalWindow->geometry() != windowRect) {
|
||||
// delay to end of cycle to prevent freeze, see BUG 384441
|
||||
QTimer::singleShot(0, m_internalWindow, std::bind(static_cast<void (QWindow::*)(const QRect&)>(&QWindow::setGeometry), m_internalWindow, windowRect));
|
||||
}
|
||||
}
|
||||
|
||||
void InternalClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
|
||||
{
|
||||
Q_UNUSED(force)
|
||||
if (!m_internalWindow) {
|
||||
return;
|
||||
}
|
||||
QRect area = workspace()->clientArea(WorkArea, this);
|
||||
// don't allow growing larger than workarea
|
||||
if (w > area.width()) {
|
||||
w = area.width();
|
||||
}
|
||||
if (h > area.height()) {
|
||||
h = area.height();
|
||||
}
|
||||
m_internalWindow->setGeometry(QRect(pos() + QPoint(borderLeft(), borderTop()), QSize(w, h) - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
|
||||
void InternalClient::doResizeSync()
|
||||
{
|
||||
if (!m_internalWindow) {
|
||||
return;
|
||||
}
|
||||
const auto rect = moveResizeGeometry();
|
||||
m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
|
||||
QWindow *InternalClient::internalWindow() const
|
||||
{
|
||||
return m_internalWindow;
|
||||
}
|
||||
|
||||
}
|
81
internal_client.h
Normal file
81
internal_client.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2019 Martin Flöser <mgraesslin@kde.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include "shell_client.h"
|
||||
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class KWIN_EXPORT InternalClient : public ShellClient
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
InternalClient(KWayland::Server::ShellSurfaceInterface *surface);
|
||||
// needed for template <class T> void WaylandServer::createSurface(T *surface)
|
||||
InternalClient(KWayland::Server::XdgShellSurfaceInterface *surface);
|
||||
// needed for template <class T> void WaylandServer::createSurface(T *surface)
|
||||
InternalClient(KWayland::Server::XdgShellPopupInterface *surface);
|
||||
~InternalClient() override;
|
||||
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
NET::WindowType windowType(bool direct = false, int supported_types = 0) const override;
|
||||
void killWindow() override;
|
||||
bool isPopupWindow() const override;
|
||||
void setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo) override;
|
||||
void closeWindow() override;
|
||||
bool isCloseable() const override;
|
||||
bool isMaximizable() const override;
|
||||
bool isMinimizable() const override;
|
||||
bool isMovable() const override;
|
||||
bool isMovableAcrossScreens() const override;
|
||||
bool isResizable() const override;
|
||||
bool noBorder() const override;
|
||||
bool userCanSetNoBorder() const override;
|
||||
bool wantsInput() const override;
|
||||
bool isInternal() const override;
|
||||
bool isLockScreen() const override;
|
||||
bool isInputMethod() const override;
|
||||
quint32 windowId() const override;
|
||||
using AbstractClient::resizeWithChecks;
|
||||
void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) override;
|
||||
QWindow *internalWindow() const override;
|
||||
|
||||
protected:
|
||||
bool acceptsFocus() const override;
|
||||
void doMove(int x, int y) override;
|
||||
void doResizeSync() override;
|
||||
bool requestGeometry(const QRect &rect) override;
|
||||
void doSetGeometry(const QRect &rect) override;
|
||||
|
||||
private:
|
||||
void findInternalWindow();
|
||||
void updateInternalWindowGeometry();
|
||||
void syncGeometryToInternalWindow();
|
||||
|
||||
NET::WindowType m_windowType = NET::Normal;
|
||||
quint32 m_windowId = 0;
|
||||
QWindow *m_internalWindow = nullptr;
|
||||
Qt::WindowFlags m_internalWindowFlags = Qt::WindowFlags();
|
||||
};
|
||||
|
||||
}
|
162
shell_client.cpp
162
shell_client.cpp
|
@ -209,7 +209,6 @@ void ShellClient::initSurface(T *shellSurface)
|
|||
void ShellClient::init()
|
||||
{
|
||||
connect(this, &ShellClient::desktopFileNameChanged, this, &ShellClient::updateIcon);
|
||||
findInternalWindow();
|
||||
createWindowId();
|
||||
setupCompositing();
|
||||
updateIcon();
|
||||
|
@ -225,10 +224,7 @@ void ShellClient::init()
|
|||
} else {
|
||||
ready_for_painting = false;
|
||||
}
|
||||
if (m_internalWindow) {
|
||||
updateInternalWindowGeometry();
|
||||
updateDecoration(true);
|
||||
} else {
|
||||
if (!m_internal) {
|
||||
doSetGeometry(QRect(QPoint(0, 0), m_clientSize));
|
||||
}
|
||||
if (waylandServer()->inputMethodConnection() == s->client()) {
|
||||
|
@ -501,20 +497,6 @@ void ShellClient::addDamage(const QRegion &damage)
|
|||
Toplevel::addDamage(damage);
|
||||
}
|
||||
|
||||
void ShellClient::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo)
|
||||
{
|
||||
if (fbo.isNull()) {
|
||||
unmap();
|
||||
return;
|
||||
}
|
||||
|
||||
m_clientSize = fbo->size() / surface()->scale();
|
||||
markAsMapped();
|
||||
doSetGeometry(QRect(geom.topLeft(), m_clientSize));
|
||||
Toplevel::setInternalFramebufferObject(fbo);
|
||||
Toplevel::addDamage(QRegion(0, 0, width(), height()));
|
||||
}
|
||||
|
||||
void ShellClient::markAsMapped()
|
||||
{
|
||||
if (!m_unmapped) {
|
||||
|
@ -635,7 +617,6 @@ void ShellClient::doSetGeometry(const QRect &rect)
|
|||
if (!m_unmapped) {
|
||||
addWorkspaceRepaint(visibleRect());
|
||||
}
|
||||
syncGeometryToInternalWindow();
|
||||
if (hasStrut()) {
|
||||
workspace()->updateClientArea();
|
||||
}
|
||||
|
@ -648,26 +629,6 @@ void ShellClient::doSetGeometry(const QRect &rect)
|
|||
}
|
||||
}
|
||||
|
||||
void ShellClient::doMove(int x, int y)
|
||||
{
|
||||
Q_UNUSED(x)
|
||||
Q_UNUSED(y)
|
||||
syncGeometryToInternalWindow();
|
||||
}
|
||||
|
||||
void ShellClient::syncGeometryToInternalWindow()
|
||||
{
|
||||
if (!m_internalWindow) {
|
||||
return;
|
||||
}
|
||||
const QRect windowRect = QRect(geom.topLeft() + QPoint(borderLeft(), borderTop()),
|
||||
geom.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
|
||||
if (m_internalWindow->geometry() != windowRect) {
|
||||
// delay to end of cycle to prevent freeze, see BUG 384441
|
||||
QTimer::singleShot(0, m_internalWindow, std::bind(static_cast<void (QWindow::*)(const QRect&)>(&QWindow::setGeometry), m_internalWindow, windowRect));
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray ShellClient::windowRole() const
|
||||
{
|
||||
return QByteArray();
|
||||
|
@ -714,8 +675,6 @@ void ShellClient::closeWindow()
|
|||
m_xdgShellSurface->close();
|
||||
const qint32 pingSerial = static_cast<XdgShellInterface *>(m_xdgShellSurface->global())->ping(m_xdgShellSurface);
|
||||
m_pingSerials.insert(pingSerial, PingReason::CloseWindow);
|
||||
} else if (m_internalWindow) {
|
||||
m_internalWindow->hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -733,9 +692,6 @@ bool ShellClient::isCloseable() const
|
|||
if (m_xdgShellSurface) {
|
||||
return true;
|
||||
}
|
||||
if (m_internal) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -746,17 +702,11 @@ bool ShellClient::isFullScreen() const
|
|||
|
||||
bool ShellClient::isMaximizable() const
|
||||
{
|
||||
if (m_internal) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShellClient::isMinimizable() const
|
||||
{
|
||||
if (m_internal) {
|
||||
return false;
|
||||
}
|
||||
return (!m_plasmaShellSurface || m_plasmaShellSurface->role() == PlasmaShellSurfaceInterface::Role::Normal);
|
||||
}
|
||||
|
||||
|
@ -924,9 +874,6 @@ MaximizeMode ShellClient::requestedMaximizeMode() const
|
|||
|
||||
bool ShellClient::noBorder() const
|
||||
{
|
||||
if (isInternal()) {
|
||||
return m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup);
|
||||
}
|
||||
if (m_serverDecoration) {
|
||||
if (m_serverDecoration->mode() == ServerSideDecorationManagerInterface::Mode::Server) {
|
||||
return m_userNoBorder || isFullScreen();
|
||||
|
@ -1062,9 +1009,6 @@ bool ShellClient::userCanSetNoBorder() const
|
|||
if (m_xdgDecoration && m_xdgDecoration->requestedMode() != XdgDecorationInterface::Mode::ClientSide) {
|
||||
return !isFullScreen() && !isShade() && !tabGroup();
|
||||
}
|
||||
if (m_internal) {
|
||||
return !m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1075,9 +1019,6 @@ bool ShellClient::wantsInput() const
|
|||
|
||||
bool ShellClient::acceptsFocus() const
|
||||
{
|
||||
if (isInternal()) {
|
||||
return false;
|
||||
}
|
||||
if (waylandServer()->inputMethodConnection() == surface()->client()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1111,56 +1052,11 @@ bool ShellClient::acceptsFocus() const
|
|||
|
||||
void ShellClient::createWindowId()
|
||||
{
|
||||
if (m_internalWindow) {
|
||||
m_windowId = m_internalWindow->winId();
|
||||
} else {
|
||||
if (!m_internal) {
|
||||
m_windowId = waylandServer()->createWindowId(surface());
|
||||
}
|
||||
}
|
||||
|
||||
void ShellClient::findInternalWindow()
|
||||
{
|
||||
if (surface()->client() != waylandServer()->internalConnection()) {
|
||||
return;
|
||||
}
|
||||
const QWindowList windows = kwinApp()->topLevelWindows();
|
||||
for (QWindow *w: windows) {
|
||||
auto s = KWayland::Client::Surface::fromWindow(w);
|
||||
if (!s) {
|
||||
continue;
|
||||
}
|
||||
if (s->id() != surface()->id()) {
|
||||
continue;
|
||||
}
|
||||
m_internalWindow = w;
|
||||
m_internalWindowFlags = m_internalWindow->flags();
|
||||
connect(m_internalWindow, &QWindow::xChanged, this, &ShellClient::updateInternalWindowGeometry);
|
||||
connect(m_internalWindow, &QWindow::yChanged, this, &ShellClient::updateInternalWindowGeometry);
|
||||
connect(m_internalWindow, &QWindow::destroyed, this, [this] { m_internalWindow = nullptr; });
|
||||
connect(m_internalWindow, &QWindow::opacityChanged, this, &ShellClient::setOpacity);
|
||||
|
||||
const QVariant windowType = m_internalWindow->property("kwin_windowType");
|
||||
if (!windowType.isNull()) {
|
||||
m_windowType = windowType.value<NET::WindowType>();
|
||||
}
|
||||
setOpacity(m_internalWindow->opacity());
|
||||
|
||||
// skip close animation support
|
||||
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
|
||||
m_internalWindow->installEventFilter(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ShellClient::updateInternalWindowGeometry()
|
||||
{
|
||||
if (!m_internalWindow) {
|
||||
return;
|
||||
}
|
||||
doSetGeometry(QRect(m_internalWindow->geometry().topLeft() - QPoint(borderLeft(), borderTop()),
|
||||
m_internalWindow->geometry().size() + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
|
||||
pid_t ShellClient::pid() const
|
||||
{
|
||||
return surface()->client()->processId();
|
||||
|
@ -1168,30 +1064,24 @@ pid_t ShellClient::pid() const
|
|||
|
||||
bool ShellClient::isInternal() const
|
||||
{
|
||||
return m_internal;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShellClient::isLockScreen() const
|
||||
{
|
||||
if (m_internalWindow) {
|
||||
return m_internalWindow->property("org_kde_ksld_emergency").toBool();
|
||||
}
|
||||
return surface()->client() == waylandServer()->screenLockerClientConnection();
|
||||
}
|
||||
|
||||
bool ShellClient::isInputMethod() const
|
||||
{
|
||||
if (m_internal && m_internalWindow) {
|
||||
return m_internalWindow->property("__kwin_input_method").toBool();
|
||||
}
|
||||
return surface()->client() == waylandServer()->inputMethodConnection();
|
||||
}
|
||||
|
||||
void ShellClient::requestGeometry(const QRect &rect)
|
||||
bool ShellClient::requestGeometry(const QRect &rect)
|
||||
{
|
||||
if (m_requestGeometryBlockCounter != 0) {
|
||||
m_blockedRequestGeometry = rect;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
PendingConfigureRequest configureRequest;
|
||||
configureRequest.positionAfterResize = rect.topLeft();
|
||||
|
@ -1218,9 +1108,7 @@ void ShellClient::requestGeometry(const QRect &rect)
|
|||
m_pendingConfigureRequests.append(configureRequest);
|
||||
|
||||
m_blockedRequestGeometry = QRect();
|
||||
if (m_internal) {
|
||||
m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShellClient::updatePendingGeometry()
|
||||
|
@ -1270,9 +1158,6 @@ void ShellClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
|
|||
if (m_xdgShellSurface) {
|
||||
m_xdgShellSurface->configure(xdgSurfaceStates(), QSize(w, h));
|
||||
}
|
||||
if (m_internal) {
|
||||
m_internalWindow->setGeometry(QRect(pos() + QPoint(borderLeft(), borderTop()), QSize(w, h) - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
|
||||
}
|
||||
}
|
||||
|
||||
void ShellClient::unmap()
|
||||
|
@ -1292,11 +1177,7 @@ void ShellClient::installPlasmaShellSurface(PlasmaShellSurfaceInterface *surface
|
|||
m_plasmaShellSurface = surface;
|
||||
auto updatePosition = [this, surface] {
|
||||
QRect rect = QRect(surface->position(), m_clientSize + QSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
|
||||
// Shell surfaces of internal windows are sometimes desync to current value.
|
||||
// Make sure to not set window geometry of internal windows to invalid values (bug 386304)
|
||||
if (!m_internal || rect.isValid()) {
|
||||
doSetGeometry(rect);
|
||||
}
|
||||
doSetGeometry(rect);
|
||||
};
|
||||
auto updateRole = [this, surface] {
|
||||
NET::WindowType type = NET::Unknown;
|
||||
|
@ -1478,22 +1359,6 @@ void ShellClient::installPalette(ServerSideDecorationPaletteInterface *palette)
|
|||
updatePalette(palette->palette());
|
||||
}
|
||||
|
||||
|
||||
bool ShellClient::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == m_internalWindow && event->type() == QEvent::DynamicPropertyChange) {
|
||||
QDynamicPropertyChangeEvent *pe = static_cast<QDynamicPropertyChangeEvent*>(event);
|
||||
if (pe->propertyName() == s_skipClosePropertyName) {
|
||||
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
|
||||
}
|
||||
if (pe->propertyName() == "kwin_windowType") {
|
||||
m_windowType = m_internalWindow->property("kwin_windowType").value<NET::WindowType>();
|
||||
workspace()->updateClientArea();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShellClient::updateColorScheme()
|
||||
{
|
||||
if (m_paletteInterface) {
|
||||
|
@ -1826,7 +1691,7 @@ void ShellClient::installXdgDecoration(XdgDecorationInterface *deco)
|
|||
|
||||
bool ShellClient::shouldExposeToWindowManagement()
|
||||
{
|
||||
if (isInternal()) {
|
||||
if (m_internal) {
|
||||
return false;
|
||||
}
|
||||
if (isLockScreen()) {
|
||||
|
@ -1916,9 +1781,6 @@ bool ShellClient::dockWantsInput() const
|
|||
|
||||
void ShellClient::killWindow()
|
||||
{
|
||||
if (isInternal()) {
|
||||
return;
|
||||
}
|
||||
if (!surface()) {
|
||||
return;
|
||||
}
|
||||
|
@ -1965,9 +1827,6 @@ bool ShellClient::isPopupWindow() const
|
|||
if (Toplevel::isPopupWindow()) {
|
||||
return true;
|
||||
}
|
||||
if (isInternal()) {
|
||||
return m_internalWindowFlags.testFlag(Qt::Popup);
|
||||
}
|
||||
if (m_shellSurface != nullptr) {
|
||||
return m_shellSurface->isPopup();
|
||||
}
|
||||
|
@ -1977,4 +1836,9 @@ bool ShellClient::isPopupWindow() const
|
|||
return false;
|
||||
}
|
||||
|
||||
QWindow *ShellClient::internalWindow() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,8 +57,6 @@ public:
|
|||
ShellClient(KWayland::Server::XdgShellPopupInterface *surface);
|
||||
virtual ~ShellClient();
|
||||
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
QStringList activities() const override;
|
||||
QPoint clientContentPos() const override;
|
||||
QSize clientSize() const override;
|
||||
|
@ -112,8 +110,6 @@ public:
|
|||
void setGeometry(int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet) override;
|
||||
bool hasStrut() const override;
|
||||
|
||||
void setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo) override;
|
||||
|
||||
quint32 windowId() const override {
|
||||
return m_windowId;
|
||||
}
|
||||
|
@ -126,12 +122,10 @@ public:
|
|||
**/
|
||||
pid_t pid() const override;
|
||||
|
||||
bool isInternal() const;
|
||||
virtual bool isInternal() const;
|
||||
bool isLockScreen() const override;
|
||||
bool isInputMethod() const override;
|
||||
QWindow *internalWindow() const {
|
||||
return m_internalWindow;
|
||||
}
|
||||
virtual QWindow *internalWindow() const;
|
||||
|
||||
void installPlasmaShellSurface(KWayland::Server::PlasmaShellSurfaceInterface *surface);
|
||||
void installServerSideDecoration(KWayland::Server::ServerSideDecorationInterface *decoration);
|
||||
|
@ -182,9 +176,21 @@ protected:
|
|||
bool isWaitingForMoveResizeSync() const override;
|
||||
bool acceptsFocus() const override;
|
||||
void doMinimize() override;
|
||||
void doMove(int x, int y) override;
|
||||
void updateCaption() override;
|
||||
|
||||
virtual bool requestGeometry(const QRect &rect);
|
||||
virtual void doSetGeometry(const QRect &rect);
|
||||
void unmap();
|
||||
void markAsMapped();
|
||||
|
||||
void setClientSize(const QSize &size) {
|
||||
m_clientSize = size;
|
||||
}
|
||||
|
||||
bool isUnmapped() const {
|
||||
return m_unmapped;
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void clientFullScreenChanged(bool fullScreen);
|
||||
|
||||
|
@ -192,17 +198,10 @@ private:
|
|||
void init();
|
||||
template <class T>
|
||||
void initSurface(T *shellSurface);
|
||||
void requestGeometry(const QRect &rect);
|
||||
void doSetGeometry(const QRect &rect);
|
||||
void createDecoration(const QRect &oldgeom);
|
||||
void destroyClient();
|
||||
void unmap();
|
||||
void createWindowId();
|
||||
void findInternalWindow();
|
||||
void updateInternalWindowGeometry();
|
||||
void syncGeometryToInternalWindow();
|
||||
void updateIcon();
|
||||
void markAsMapped();
|
||||
void setTransient();
|
||||
bool shouldExposeToWindowManagement();
|
||||
void updateClientOutputs();
|
||||
|
@ -243,8 +242,6 @@ private:
|
|||
QRect m_geomFsRestore; //size and position of the window before it was set to fullscreen
|
||||
bool m_closing = false;
|
||||
quint32 m_windowId = 0;
|
||||
QWindow *m_internalWindow = nullptr;
|
||||
Qt::WindowFlags m_internalWindowFlags = Qt::WindowFlags();
|
||||
bool m_unmapped = true;
|
||||
QRect m_geomMaximizeRestore; // size and position of the window before it was set to maximize
|
||||
NET::WindowType m_windowType = NET::Normal;
|
||||
|
|
|
@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "platform.h"
|
||||
#include "composite.h"
|
||||
#include "idle_inhibition.h"
|
||||
#include "internal_client.h"
|
||||
#include "screens.h"
|
||||
#include "shell_client.h"
|
||||
#include "workspace.h"
|
||||
|
@ -155,7 +156,13 @@ void WaylandServer::createSurface(T *surface)
|
|||
if (surface->client() == m_screenLockerClientConnection) {
|
||||
ScreenLocker::KSldApp::self()->lockScreenShown();
|
||||
}
|
||||
auto client = new ShellClient(surface);
|
||||
ShellClient *client;
|
||||
if (surface->client() == waylandServer()->internalConnection()) {
|
||||
client = new InternalClient(surface);
|
||||
} else {
|
||||
client = new ShellClient(surface);
|
||||
}
|
||||
client = new ShellClient(surface);
|
||||
if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) {
|
||||
client->installServerSideDecoration(deco);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue