Port QPA away from Wayland

Summary:
So far wayland was used by internal clients to submit raster buffers
and position themselves on the screen. While we didn't have issues with
submitting raster buffers, there were some problems with positioning
task switchers. Mostly, because we had effectively two paths that may
alter geometry.

A better approach to deal with internal clients is to let our QPA use
kwin core api directly. This way we can eliminate unnecessary roundtrips
as well make geometry handling much easier and comprehensible.

The last missing piece is shadows. Both Plasma::Dialog and Breeze widget
style use platform-specific APIs to set and unset shadows. We need to
add shadows API to KWindowSystem. Even though some internal clients lack
drop-shadows at the moment, I don't consider it to be a blocker. We can
add shadows back later on.

CCBUG: 386304

Reviewers: #kwin, davidedmundson, romangg

Reviewed By: #kwin, romangg

Subscribers: romangg, kwin

Tags: #kwin

Maniphest Tasks: T9600

Differential Revision: https://phabricator.kde.org/D22810
This commit is contained in:
Vlad Zagorodniy 2019-08-26 10:44:04 +03:00 committed by Vlad Zahorodnii
parent ca1f66b1df
commit bebe81209c
45 changed files with 1128 additions and 893 deletions

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -1992,4 +1993,9 @@ bool AbstractClient::supportsWindowRules() const
return true;
}
QMargins AbstractClient::frameMargins() const
{
return QMargins(borderLeft(), borderTop(), borderRight(), borderBottom());
}
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -834,6 +835,14 @@ public:
*/
virtual bool supportsWindowRules() const;
/**
* Returns the extents of the server-side decoration.
*
* Note that the returned margins object will have all margins set to 0 if
* the client doesn't have a server-side decoration.
*/
QMargins frameMargins() const;
public Q_SLOTS:
virtual void closeWindow() = 0;

View file

@ -18,11 +18,13 @@ 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 "kwin_wayland_test.h"
#include "platform.h"
#include "debug_console.h"
#include "internal_client.h"
#include "platform.h"
#include "screens.h"
#include "shell_client.h"
#include "wayland_server.h"
#include "workspace.h"
#include "xcbutils.h"
#include <KWayland/Client/connection_thread.h>
@ -57,8 +59,9 @@ private Q_SLOTS:
void DebugConsoleTest::initTestCase()
{
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
qRegisterMetaType<KWin::AbstractClient *>();
qRegisterMetaType<KWin::InternalClient *>();
qRegisterMetaType<KWin::ShellClient *>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
@ -497,8 +500,7 @@ void DebugConsoleTest::testInternalWindow()
w->hide();
w.reset();
QVERIFY(rowsRemovedSpy.wait());
QCOMPARE(rowsRemovedSpy.count(), 1);
QTRY_COMPARE(rowsRemovedSpy.count(), 1);
QCOMPARE(rowsRemovedSpy.first().first().value<QModelIndex>(), internalTopLevelIndex);
}
@ -511,12 +513,12 @@ void DebugConsoleTest::testClosingDebugConsole()
QSignalSpy destroyedSpy(console, &QObject::destroyed);
QVERIFY(destroyedSpy.isValid());
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
console->show();
QCOMPARE(console->windowHandle()->isVisible(), true);
QTRY_COMPARE(clientAddedSpy.count(), 1);
ShellClient *c = clientAddedSpy.first().first().value<ShellClient*>();
InternalClient *c = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(c->isInternal());
QCOMPARE(c->internalWindow(), console->windowHandle());
QVERIFY(c->isDecorated());

View file

@ -18,16 +18,17 @@ 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 "kwin_wayland_test.h"
#include "platform.h"
#include "abstract_client.h"
#include "cursor.h"
#include "internal_client.h"
#include "platform.h"
#include "pointer_input.h"
#include "touch_input.h"
#include "screenedge.h"
#include "screens.h"
#include "shell_client.h"
#include "wayland_server.h"
#include "workspace.h"
#include "shell_client.h"
#include <kwineffects.h>
#include "decorations/decoratedclient.h"
@ -133,8 +134,9 @@ AbstractClient *DecorationInputTest::showWindow(Test::ShellSurfaceType type)
void DecorationInputTest::initTestCase()
{
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
qRegisterMetaType<KWin::AbstractClient *>();
qRegisterMetaType<KWin::InternalClient *>();
qRegisterMetaType<KWin::ShellClient *>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
@ -910,12 +912,12 @@ void DecorationInputTest::testTooltipDoesntEatKeyEvents()
QSignalSpy keyEvent(keyboard, &KWayland::Client::Keyboard::keyChanged);
QVERIFY(keyEvent.isValid());
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
c->decoratedClient()->requestShowToolTip(QStringLiteral("test"));
// now we should get an internal window
QVERIFY(clientAddedSpy.wait());
ShellClient *internal = clientAddedSpy.first().first().value<ShellClient*>();
InternalClient *internal = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internal->isInternal());
QVERIFY(internal->internalWindow()->flags().testFlag(Qt::ToolTip));

View file

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "deleted.h"
#include "effectloader.h"
#include "effects.h"
#include "internal_client.h"
#include "platform.h"
#include "shell_client.h"
#include "useractions.h"
@ -64,6 +65,7 @@ void PopupOpenCloseAnimationTest::initTestCase()
qRegisterMetaType<KWin::AbstractClient *>();
qRegisterMetaType<KWin::Deleted *>();
qRegisterMetaType<KWin::InternalClient *>();
qRegisterMetaType<KWin::ShellClient *>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
@ -248,11 +250,11 @@ void PopupOpenCloseAnimationTest::testAnimateDecorationTooltips()
QVERIFY(!effect->isActive());
// Show a decoration tooltip.
QSignalSpy tooltipAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy tooltipAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(tooltipAddedSpy.isValid());
client->decoratedClient()->requestShowToolTip(QStringLiteral("KWin rocks!"));
QVERIFY(tooltipAddedSpy.wait());
ShellClient *tooltip = tooltipAddedSpy.first().first().value<ShellClient *>();
InternalClient *tooltip = tooltipAddedSpy.first().first().value<InternalClient *>();
QVERIFY(tooltip->isInternal());
QVERIFY(tooltip->isPopupWindow());
QVERIFY(tooltip->internalWindow()->flags().testFlag(Qt::ToolTip));
@ -262,7 +264,7 @@ void PopupOpenCloseAnimationTest::testAnimateDecorationTooltips()
QTRY_VERIFY(!effect->isActive());
// Hide the decoration tooltip.
QSignalSpy tooltipClosedSpy(tooltip, &ShellClient::windowClosed);
QSignalSpy tooltipClosedSpy(tooltip, &InternalClient::windowClosed);
QVERIFY(tooltipClosedSpy.isValid());
client->decoratedClient()->requestHideToolTip();
QVERIFY(tooltipClosedSpy.wait());

View file

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "client.h"
#include "cursor.h"
#include "input.h"
#include "internal_client.h"
#include "platform.h"
#include "screens.h"
#include "shell_client.h"
@ -63,8 +64,9 @@ private Q_SLOTS:
void GlobalShortcutsTest::initTestCase()
{
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
qRegisterMetaType<KWin::AbstractClient *>();
qRegisterMetaType<KWin::InternalClient *>();
qRegisterMetaType<KWin::ShellClient *>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
@ -346,11 +348,11 @@ void GlobalShortcutsTest::testSetupWindowShortcut()
QVERIFY(client->isActive());
QCOMPARE(client->shortcut(), QKeySequence());
QSignalSpy shortcutDialogAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy shortcutDialogAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(shortcutDialogAddedSpy.isValid());
workspace()->slotSetupWindowShortcut();
QTRY_COMPARE(shortcutDialogAddedSpy.count(), 1);
auto dialog = shortcutDialogAddedSpy.first().first().value<ShellClient*>();
auto dialog = shortcutDialogAddedSpy.first().first().value<InternalClient *>();
QVERIFY(dialog);
QVERIFY(dialog->isInternal());
auto sequenceEdit = workspace()->shortcutDialog()->findChild<QKeySequenceEdit*>();

View file

@ -22,8 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "cursor.h"
#include "effects.h"
#include "internal_client.h"
#include "shell_client.h"
#include "screens.h"
#include "shell_client.h"
#include "wayland_server.h"
#include "workspace.h"
@ -184,8 +184,9 @@ void HelperWindow::keyReleaseEvent(QKeyEvent *event)
void InternalWindowTest::initTestCase()
{
qRegisterMetaType<KWin::ShellClient*>();
qRegisterMetaType<KWin::AbstractClient*>();
qRegisterMetaType<KWin::AbstractClient *>();
qRegisterMetaType<KWin::InternalClient *>();
qRegisterMetaType<KWin::ShellClient *>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
@ -211,26 +212,27 @@ void InternalWindowTest::init()
void InternalWindowTest::cleanup()
{
Test::destroyWaylandConnection();
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2));
}
void InternalWindowTest::testEnterLeave()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
QVERIFY(!workspace()->findToplevel(nullptr));
QVERIFY(!workspace()->findToplevel(&win));
QVERIFY(!workspace()->findInternal(nullptr));
QVERIFY(!workspace()->findInternal(&win));
win.setGeometry(0, 0, 100, 100);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
QVERIFY(!workspace()->activeClient());
ShellClient *c = clientAddedSpy.first().first().value<ShellClient*>();
InternalClient *c = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(c);
QVERIFY(c->isInternal());
QVERIFY(qobject_cast<InternalClient*>(c));
QCOMPARE(c->icon().name(), QStringLiteral("wayland"));
QVERIFY(!c->isDecorated());
QCOMPARE(workspace()->findToplevel(&win), c);
QCOMPARE(workspace()->findInternal(&win), c);
QCOMPARE(c->geometry(), QRect(0, 0, 100, 100));
QVERIFY(c->isShown(false));
QVERIFY(workspace()->xStackingOrder().contains(c));
@ -262,21 +264,11 @@ void InternalWindowTest::testEnterLeave()
// inside the mask we should still get an enter
kwinApp()->platform()->pointerMotion(QPoint(25, 27), timestamp++);
QTRY_COMPARE(enterSpy.count(), 2);
// hide the window, which should be removed from the stacking order
win.hide();
QTRY_VERIFY(!c->isShown(false));
QVERIFY(!workspace()->xStackingOrder().contains(c));
// show again
win.show();
QTRY_VERIFY(c->isShown(false));
QVERIFY(workspace()->xStackingOrder().contains(c));
}
void InternalWindowTest::testPointerPressRelease()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -299,7 +291,7 @@ void InternalWindowTest::testPointerPressRelease()
void InternalWindowTest::testPointerAxis()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -327,7 +319,7 @@ void InternalWindowTest::testKeyboard_data()
void InternalWindowTest::testKeyboard()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -337,7 +329,7 @@ void InternalWindowTest::testKeyboard()
QSignalSpy releaseSpy(&win, &HelperWindow::keyReleased);
QVERIFY(releaseSpy.isValid());
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->isInternal());
QVERIFY(internalClient->readyForPainting());
@ -356,7 +348,7 @@ void InternalWindowTest::testKeyboard()
void InternalWindowTest::testKeyboardShowWithoutActivating()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setProperty("_q_showWithoutActivating", true);
@ -367,7 +359,7 @@ void InternalWindowTest::testKeyboardShowWithoutActivating()
QSignalSpy releaseSpy(&win, &HelperWindow::keyReleased);
QVERIFY(releaseSpy.isValid());
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->isInternal());
QVERIFY(internalClient->readyForPainting());
@ -412,7 +404,7 @@ void InternalWindowTest::testKeyboardTriggersLeave()
QCOMPARE(enteredSpy.count(), 1);
// create internal window
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -422,7 +414,7 @@ void InternalWindowTest::testKeyboardTriggersLeave()
QSignalSpy releaseSpy(&win, &HelperWindow::keyReleased);
QVERIFY(releaseSpy.isValid());
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->isInternal());
QVERIFY(internalClient->readyForPainting());
@ -449,7 +441,7 @@ void InternalWindowTest::testKeyboardTriggersLeave()
void InternalWindowTest::testTouch()
{
// touch events for internal windows are emulated through mouse events
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -513,20 +505,20 @@ void InternalWindowTest::testTouch()
void InternalWindowTest::testOpacity()
{
// this test verifies that opacity is properly synced from QWindow to ShellClient
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
// this test verifies that opacity is properly synced from QWindow to InternalClient
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setOpacity(0.5);
win.setGeometry(0, 0, 100, 100);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->isInternal());
QCOMPARE(internalClient->opacity(), 0.5);
QSignalSpy opacityChangedSpy(internalClient, &ShellClient::opacityChanged);
QSignalSpy opacityChangedSpy(internalClient, &InternalClient::opacityChanged);
QVERIFY(opacityChangedSpy.isValid());
win.setOpacity(0.75);
QCOMPARE(opacityChangedSpy.count(), 1);
@ -535,14 +527,14 @@ void InternalWindowTest::testOpacity()
void InternalWindowTest::testMove()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setOpacity(0.5);
win.setGeometry(0, 0, 100, 100);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QCOMPARE(internalClient->geometry(), QRect(0, 0, 100, 100));
@ -576,7 +568,7 @@ void InternalWindowTest::testSkipCloseAnimation_data()
void InternalWindowTest::testSkipCloseAnimation()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setOpacity(0.5);
@ -585,7 +577,7 @@ void InternalWindowTest::testSkipCloseAnimation()
win.setProperty("KWIN_SKIP_CLOSE_ANIMATION", initial);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QCOMPARE(internalClient->skipsCloseAnimation(), initial);
QSignalSpy skipCloseChangedSpy(internalClient, &Toplevel::skipCloseAnimationChanged);
@ -600,14 +592,14 @@ void InternalWindowTest::testSkipCloseAnimation()
void InternalWindowTest::testModifierClickUnrestrictedMove()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
win.setFlags(win.flags() & ~Qt::FramelessWindowHint);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->isDecorated());
@ -642,14 +634,14 @@ void InternalWindowTest::testModifierClickUnrestrictedMove()
void InternalWindowTest::testModifierScroll()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
win.setFlags(win.flags() & ~Qt::FramelessWindowHint);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->isDecorated());
@ -676,14 +668,14 @@ void InternalWindowTest::testModifierScroll()
void InternalWindowTest::testPopup()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
win.setFlags(win.flags() | Qt::Popup);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QCOMPARE(internalClient->isPopupWindow(), true);
}
@ -695,7 +687,7 @@ void InternalWindowTest::testScale()
Q_ARG(QVector<QRect>, QVector<QRect>({QRect(0,0,1280, 1024), QRect(1280/2, 0, 1280, 1024)})),
Q_ARG(QVector<int>, QVector<int>({2,2})));
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -703,10 +695,8 @@ void InternalWindowTest::testScale()
win.show();
QCOMPARE(win.devicePixelRatio(), 2.0);
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
QCOMPARE(internalClient->surface()->scale(), 2);
QMetaObject::invokeMethod(kwinApp()->platform(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(int, 2));
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QCOMPARE(internalClient->bufferScale(), 2);
}
void InternalWindowTest::testWindowType_data()
@ -732,7 +722,7 @@ void InternalWindowTest::testWindowType_data()
void InternalWindowTest::testWindowType()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
@ -740,7 +730,7 @@ void InternalWindowTest::testWindowType()
KWindowSystem::setType(win.winId(), windowType);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QCOMPARE(internalClient->windowType(), windowType);
}
@ -767,13 +757,13 @@ void InternalWindowTest::testChangeWindowType_data()
void InternalWindowTest::testChangeWindowType()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QCOMPARE(internalClient->windowType(), NET::Normal);
@ -787,13 +777,13 @@ void InternalWindowTest::testChangeWindowType()
void InternalWindowTest::testEffectWindow()
{
QSignalSpy clientAddedSpy(waylandServer(), &WaylandServer::shellClientAdded);
QSignalSpy clientAddedSpy(workspace(), &Workspace::internalClientAdded);
QVERIFY(clientAddedSpy.isValid());
HelperWindow win;
win.setGeometry(0, 0, 100, 100);
win.show();
QTRY_COMPARE(clientAddedSpy.count(), 1);
auto internalClient = clientAddedSpy.first().first().value<ShellClient*>();
auto internalClient = clientAddedSpy.first().first().value<InternalClient *>();
QVERIFY(internalClient);
QVERIFY(internalClient->effectWindow());
QCOMPARE(internalClient->effectWindow()->internalWindow(), &win);

View file

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "decorations/decoratedclient.h"
#include "deleted.h"
#include "effects.h"
#include "internal_client.h"
#include "overlaywindow.h"
#include "platform.h"
#include "scene.h"
@ -357,6 +358,10 @@ void Compositor::startupWithWorkspace()
c->setupCompositing();
c->getShadow();
}
for (InternalClient *client : workspace()->internalClients()) {
client->setupCompositing();
client->getShadow();
}
if (auto *server = waylandServer()) {
const auto clients = server->clients();
@ -364,11 +369,6 @@ void Compositor::startupWithWorkspace()
c->setupCompositing();
c->getShadow();
}
const auto internalClients = server->internalClients();
for (ShellClient *c : internalClients) {
c->setupCompositing();
c->getShadow();
}
}
m_state = State::On;
@ -415,6 +415,9 @@ void Compositor::stop()
for (Unmanaged *c : Workspace::self()->unmanagedList()) {
m_scene->removeToplevel(c);
}
for (InternalClient *client : workspace()->internalClients()) {
m_scene->removeToplevel(client);
}
for (Client *c : Workspace::self()->clientList()) {
c->finishCompositing();
}
@ -424,6 +427,9 @@ void Compositor::stop()
for (Unmanaged *c : Workspace::self()->unmanagedList()) {
c->finishCompositing();
}
for (InternalClient *client : workspace()->internalClients()) {
client->finishCompositing();
}
if (auto *con = kwinApp()->x11Connection()) {
xcb_composite_unredirect_subwindows(con, kwinApp()->x11RootWindow(),
XCB_COMPOSITE_REDIRECT_MANUAL);
@ -437,15 +443,9 @@ void Compositor::stop()
for (ShellClient *c : waylandServer()->clients()) {
m_scene->removeToplevel(c);
}
for (ShellClient *c : waylandServer()->internalClients()) {
m_scene->removeToplevel(c);
}
for (ShellClient *c : waylandServer()->clients()) {
c->finishCompositing();
}
for (ShellClient *c : waylandServer()->internalClients()) {
c->finishCompositing();
}
}
delete m_scene;
@ -754,14 +754,14 @@ bool Compositor::windowRepaintsPending() const
if (std::any_of(clients.begin(), clients.end(), test)) {
return true;
}
const auto &internalClients = server->internalClients();
auto internalTest = [](ShellClient *c) {
return c->isShown(true) && !c->repaints().isEmpty();
}
const auto &internalClients = workspace()->internalClients();
auto internalTest = [] (InternalClient *client) {
return client->isShown(true) && !client->repaints().isEmpty();
};
if (std::any_of(internalClients.begin(), internalClients.end(), internalTest)) {
return true;
}
}
return false;
}

View file

@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "composite.h"
#include "client.h"
#include "input_event.h"
#include "internal_client.h"
#include "main.h"
#include "scene.h"
#include "shell_client.h"
@ -762,7 +763,7 @@ QString DebugConsoleDelegate::displayText(const QVariant &value, const QLocale &
static const int s_x11ClientId = 1;
static const int s_x11UnmanagedId = 2;
static const int s_waylandClientId = 3;
static const int s_waylandInternalId = 4;
static const int s_workspaceInternalId = 4;
static const quint32 s_propertyBitMask = 0xFFFF0000;
static const quint32 s_clientBitMask = 0x0000FFFF;
static const quint32 s_idDistance = 10000;
@ -795,23 +796,14 @@ DebugConsoleModel::DebugConsoleModel(QObject *parent)
for (auto c : clients) {
m_shellClients.append(c);
}
const auto internals = waylandServer()->internalClients();
for (auto c : internals) {
m_internalClients.append(c);
}
// TODO: that only includes windows getting shown, not those which are only created
connect(waylandServer(), &WaylandServer::shellClientAdded, this,
[this] (ShellClient *c) {
if (c->isInternal()) {
add(s_waylandInternalId -1, m_internalClients, c);
} else {
add(s_waylandClientId -1, m_shellClients, c);
}
}
);
connect(waylandServer(), &WaylandServer::shellClientRemoved, this,
[this] (ShellClient *c) {
remove(s_waylandInternalId -1, m_internalClients, c);
remove(s_waylandClientId -1, m_shellClients, c);
}
);
@ -853,6 +845,19 @@ DebugConsoleModel::DebugConsoleModel(QObject *parent)
remove(s_x11UnmanagedId -1, m_unmanageds, u);
}
);
for (InternalClient *client : workspace()->internalClients()) {
m_internalClients.append(client);
}
connect(workspace(), &Workspace::internalClientAdded, this,
[this](InternalClient *client) {
add(s_workspaceInternalId -1, m_internalClients, client);
}
);
connect(workspace(), &Workspace::internalClientRemoved, this,
[this](InternalClient *client) {
remove(s_workspaceInternalId -1, m_internalClients, client);
}
);
}
DebugConsoleModel::~DebugConsoleModel() = default;
@ -890,7 +895,7 @@ int DebugConsoleModel::rowCount(const QModelIndex &parent) const
return m_unmanageds.count();
case s_waylandClientId:
return m_shellClients.count();
case s_waylandInternalId:
case s_workspaceInternalId:
return m_internalClients.count();
default:
break;
@ -907,7 +912,7 @@ int DebugConsoleModel::rowCount(const QModelIndex &parent) const
return propertyCount(parent, &DebugConsoleModel::unmanaged);
} else if (parent.internalId() < s_idDistance * (s_waylandClientId + 1)) {
return propertyCount(parent, &DebugConsoleModel::shellClient);
} else if (parent.internalId() < s_idDistance * (s_waylandInternalId + 1)) {
} else if (parent.internalId() < s_idDistance * (s_workspaceInternalId + 1)) {
return propertyCount(parent, &DebugConsoleModel::internalClient);
}
@ -959,8 +964,8 @@ QModelIndex DebugConsoleModel::index(int row, int column, const QModelIndex &par
return indexForClient(row, column, m_unmanageds, s_x11UnmanagedId);
case s_waylandClientId:
return indexForClient(row, column, m_shellClients, s_waylandClientId);
case s_waylandInternalId:
return indexForClient(row, column, m_internalClients, s_waylandInternalId);
case s_workspaceInternalId:
return indexForClient(row, column, m_internalClients, s_workspaceInternalId);
default:
break;
}
@ -972,7 +977,7 @@ QModelIndex DebugConsoleModel::index(int row, int column, const QModelIndex &par
return indexForProperty(row, column, parent, &DebugConsoleModel::unmanaged);
} else if (parent.internalId() < s_idDistance * (s_waylandClientId + 1)) {
return indexForProperty(row, column, parent, &DebugConsoleModel::shellClient);
} else if (parent.internalId() < s_idDistance * (s_waylandInternalId + 1)) {
} else if (parent.internalId() < s_idDistance * (s_workspaceInternalId + 1)) {
return indexForProperty(row, column, parent, &DebugConsoleModel::internalClient);
}
@ -981,7 +986,7 @@ QModelIndex DebugConsoleModel::index(int row, int column, const QModelIndex &par
QModelIndex DebugConsoleModel::parent(const QModelIndex &child) const
{
if (child.internalId() <= s_waylandInternalId) {
if (child.internalId() <= s_workspaceInternalId) {
return QModelIndex();
}
if (child.internalId() & s_propertyBitMask) {
@ -993,8 +998,8 @@ QModelIndex DebugConsoleModel::parent(const QModelIndex &child) const
return createIndex(parentId - (s_idDistance * s_x11UnmanagedId), 0, parentId);
} else if (parentId < s_idDistance * (s_waylandClientId + 1)) {
return createIndex(parentId - (s_idDistance * s_waylandClientId), 0, parentId);
} else if (parentId < s_idDistance * (s_waylandInternalId + 1)) {
return createIndex(parentId - (s_idDistance * s_waylandInternalId), 0, parentId);
} else if (parentId < s_idDistance * (s_workspaceInternalId + 1)) {
return createIndex(parentId - (s_idDistance * s_workspaceInternalId), 0, parentId);
}
return QModelIndex();
}
@ -1004,8 +1009,8 @@ QModelIndex DebugConsoleModel::parent(const QModelIndex &child) const
return createIndex(s_x11UnmanagedId -1, 0, s_x11UnmanagedId);
} else if (child.internalId() < s_idDistance * (s_waylandClientId + 1)) {
return createIndex(s_waylandClientId -1, 0, s_waylandClientId);
} else if (child.internalId() < s_idDistance * (s_waylandInternalId + 1)) {
return createIndex(s_waylandInternalId -1, 0, s_waylandInternalId);
} else if (child.internalId() < s_idDistance * (s_workspaceInternalId + 1)) {
return createIndex(s_workspaceInternalId -1, 0, s_workspaceInternalId);
}
return QModelIndex();
}
@ -1098,7 +1103,7 @@ QVariant DebugConsoleModel::data(const QModelIndex &index, int role) const
return i18n("X11 Unmanaged Windows");
case s_waylandClientId:
return i18n("Wayland Windows");
case s_waylandInternalId:
case s_workspaceInternalId:
return i18n("Internal Windows");
default:
return QVariant();
@ -1110,7 +1115,7 @@ QVariant DebugConsoleModel::data(const QModelIndex &index, int role) const
}
if (ShellClient *c = shellClient(index)) {
return propertyData(c, index, role);
} else if (ShellClient *c = internalClient(index)) {
} else if (InternalClient *c = internalClient(index)) {
return propertyData(c, index, role);
} else if (Client *c = x11Client(index)) {
return propertyData(c, index, role);
@ -1136,7 +1141,7 @@ QVariant DebugConsoleModel::data(const QModelIndex &index, int role) const
}
case s_waylandClientId:
return clientData(index, role, m_shellClients);
case s_waylandInternalId:
case s_workspaceInternalId:
return clientData(index, role, m_internalClients);
default:
break;
@ -1161,9 +1166,9 @@ ShellClient *DebugConsoleModel::shellClient(const QModelIndex &index) const
return clientForIndex(index, m_shellClients, s_waylandClientId);
}
ShellClient *DebugConsoleModel::internalClient(const QModelIndex &index) const
InternalClient *DebugConsoleModel::internalClient(const QModelIndex &index) const
{
return clientForIndex(index, m_internalClients, s_waylandInternalId);
return clientForIndex(index, m_internalClients, s_workspaceInternalId);
}
Client *DebugConsoleModel::x11Client(const QModelIndex &index) const
@ -1207,9 +1212,6 @@ SurfaceTreeModel::SurfaceTreeModel(QObject *parent)
connect(c->surface(), &SurfaceInterface::subSurfaceTreeChanged, this, reset);
}
if (waylandServer()) {
for (auto c : waylandServer()->internalClients()) {
connect(c->surface(), &SurfaceInterface::subSurfaceTreeChanged, this, reset);
}
connect(waylandServer(), &WaylandServer::shellClientAdded, this,
[this, reset] (ShellClient *c) {
connect(c->surface(), &SurfaceInterface::subSurfaceTreeChanged, this, reset);
@ -1255,12 +1257,10 @@ int SurfaceTreeModel::rowCount(const QModelIndex &parent) const
}
return 0;
}
const int internalClientsCount = waylandServer() ? waylandServer()->internalClients().count() : 0;
// toplevel are all windows
return workspace()->allClientList().count() +
workspace()->desktopList().count() +
workspace()->unmanagedList().count() +
internalClientsCount;
workspace()->unmanagedList().count();
}
QModelIndex SurfaceTreeModel::index(int row, int column, const QModelIndex &parent) const
@ -1297,12 +1297,6 @@ QModelIndex SurfaceTreeModel::index(int row, int column, const QModelIndex &pare
return createIndex(row, column, unmanaged.at(row-reference)->surface());
}
reference += unmanaged.count();
if (waylandServer()) {
const auto &internal = waylandServer()->internalClients();
if (row < reference + internal.count()) {
return createIndex(row, column, internal.at(row-reference)->surface());
}
}
// not found
return QModelIndex();
}
@ -1359,14 +1353,6 @@ QModelIndex SurfaceTreeModel::parent(const QModelIndex &child) const
}
}
row += unmanaged.count();
if (waylandServer()) {
const auto &internal = waylandServer()->internalClients();
for (int i = 0; i < internal.count(); i++) {
if (internal.at(i)->surface() == parent) {
return createIndex(row + i, 0, parent);
}
}
}
}
return QModelIndex();
}

View file

@ -40,6 +40,7 @@ namespace KWin
{
class Client;
class InternalClient;
class ShellClient;
class Unmanaged;
class DebugConsoleFilter;
@ -73,13 +74,13 @@ private:
template <class T>
void remove(int parentRow, QVector<T*> &clients, T *client);
ShellClient *shellClient(const QModelIndex &index) const;
ShellClient *internalClient(const QModelIndex &index) const;
InternalClient *internalClient(const QModelIndex &index) const;
Client *x11Client(const QModelIndex &index) const;
Unmanaged *unmanaged(const QModelIndex &index) const;
int topLevelRowCount() const;
QVector<ShellClient*> m_shellClients;
QVector<ShellClient*> m_internalClients;
QVector<InternalClient*> m_internalClients;
QVector<Client*> m_x11Clients;
QVector<Unmanaged*> m_unmanageds;

View file

@ -94,6 +94,7 @@ void Deleted::copyToDeleted(Toplevel* c)
{
Q_ASSERT(dynamic_cast< Deleted* >(c) == nullptr);
Toplevel::copyToDeleted(c);
m_bufferScale = c->bufferScale();
desk = c->desktop();
m_desktops = c->desktops();
activityList = c->activities();
@ -146,7 +147,7 @@ void Deleted::copyToDeleted(Toplevel* c)
}
m_wasWaylandClient = qobject_cast<ShellClient *>(c) != nullptr;
m_wasX11Client = !m_wasWaylandClient;
m_wasX11Client = qobject_cast<Client *>(c) != nullptr;
m_wasPopupWindow = c->isPopupWindow();
m_wasOutline = c->isOutline();
}
@ -162,6 +163,11 @@ void Deleted::unrefWindow()
deleteLater();
}
qreal Deleted::bufferScale() const
{
return m_bufferScale;
}
int Deleted::desktop() const
{
return desk;

View file

@ -44,6 +44,7 @@ public:
void refWindow();
void unrefWindow();
void discard();
qreal bufferScale() const override;
int desktop() const override;
QStringList activities() const override;
QVector<VirtualDesktop *> desktops() const override;
@ -233,6 +234,7 @@ private:
DeletedList m_transients;
bool m_wasPopupWindow;
bool m_wasOutline;
qreal m_bufferScale = 1;
};
inline void Deleted::refWindow()

View file

@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "client.h"
#include "cursor.h"
#include "group.h"
#include "internal_client.h"
#include "osd.h"
#include "pointer_input.h"
#include "unmanaged.h"
@ -178,6 +179,12 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
connect(u, &Toplevel::windowShown, this, &EffectsHandlerImpl::slotUnmanagedShown);
}
);
connect(ws, &Workspace::internalClientAdded, this,
[this](InternalClient *client) {
setupAbstractClientConnections(client);
emit windowAdded(client->effectWindow());
}
);
connect(ws, &Workspace::clientActivated, this,
[this](KWin::AbstractClient *c) {
emit windowActivated(c ? c->effectWindow() : nullptr);
@ -245,6 +252,9 @@ EffectsHandlerImpl::EffectsHandlerImpl(Compositor *compositor, Scene *scene)
for (Unmanaged *u : ws->unmanagedList()) {
setupUnmanagedConnections(u);
}
for (InternalClient *client : ws->internalClients()) {
setupAbstractClientConnections(client);
}
if (auto w = waylandServer()) {
connect(w, &WaylandServer::shellClientAdded, this,
[this](ShellClient *c) {
@ -1087,13 +1097,8 @@ EffectWindow* EffectsHandlerImpl::findWindow(KWayland::Server::SurfaceInterface
EffectWindow *EffectsHandlerImpl::findWindow(QWindow *w) const
{
if (waylandServer()) {
if (auto c = waylandServer()->findClient(w)) {
return c->effectWindow();
}
}
if (auto u = Workspace::self()->findUnmanaged(w->winId())) {
return u->effectWindow();
if (Toplevel *toplevel = workspace()->findInternal(w)) {
return toplevel->effectWindow();
}
return nullptr;
}
@ -1716,7 +1721,7 @@ EffectWindowImpl::EffectWindowImpl(Toplevel *toplevel)
managed = toplevel->isClient();
waylandClient = qobject_cast<KWin::ShellClient *>(toplevel) != nullptr;
x11Client = !waylandClient;
x11Client = qobject_cast<KWin::Client *>(toplevel) != nullptr;
}
EffectWindowImpl::~EffectWindowImpl()
@ -1969,7 +1974,7 @@ EffectWindow* EffectWindowImpl::findModal()
QWindow *EffectWindowImpl::internalWindow() const
{
auto client = qobject_cast<ShellClient*>(toplevel);
auto client = qobject_cast<InternalClient *>(toplevel);
if (!client) {
return nullptr;
}

View file

@ -39,6 +39,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "screens.h"
#include "effects.h"
#include "screenedge.h"
#include "internal_client.h"
#include <QApplication>
#include <QDebug>
#include <QVarLengthArray>
@ -268,10 +269,6 @@ void Workspace::updateClientArea(bool force)
for (auto c : clients) {
updateStrutsForWaylandClient(c);
}
const auto internalClients = waylandServer()->internalClients();
for (auto c : internalClients) {
updateStrutsForWaylandClient(c);
}
}
#if 0
for (int i = 1;

View file

@ -94,6 +94,10 @@ void IdleInhibition::uninhibit(AbstractClient *client)
void IdleInhibition::update(AbstractClient *client)
{
if (client->isInternal()) {
return;
}
// TODO: Don't honor the idle inhibitor object if the shell client is not
// on the current activity (currently, activities are not supported).
const bool visible = client->isShown(true) && client->isOnCurrentDesktop();

View file

@ -46,6 +46,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "shell_client.h"
#include "wayland_server.h"
#include "xwl/xwayland_interface.h"
#include "internal_client.h"
#include <KWayland/Server/display.h>
#include <KWayland/Server/fakeinput_interface.h>
#include <KWayland/Server/seat_interface.h>
@ -818,7 +819,7 @@ class InternalWindowEventFilter : public InputEventFilter {
{
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease: {
auto s = waylandServer()->findClient(internal);
auto s = qobject_cast<InternalClient *>(workspace()->findInternal(internal));
if (s && s->isDecorated()) {
// only perform mouse commands on decorated internal windows
const auto actionResult = performClientMouseAction(event, s);
@ -845,7 +846,7 @@ class InternalWindowEventFilter : public InputEventFilter {
return false;
}
if (event->angleDelta().y() != 0) {
auto s = waylandServer()->findClient(internal);
auto s = qobject_cast<InternalClient *>(workspace()->findInternal(internal));
if (s && s->isDecorated()) {
// client window action only on vertical scrolling
const auto actionResult = performClientWheelAction(event, s);
@ -868,7 +869,7 @@ class InternalWindowEventFilter : public InputEventFilter {
return e.isAccepted();
}
bool keyEvent(QKeyEvent *event) override {
const auto &internalClients = waylandServer()->internalClients();
const QList<InternalClient *> &internalClients = workspace()->internalClients();
if (internalClients.isEmpty()) {
return false;
}
@ -2349,7 +2350,7 @@ void InputDeviceHandler::update()
const auto pos = position().toPoint();
internalWindow = findInternalWindow(pos);
if (internalWindow) {
toplevel = waylandServer()->findClient(internalWindow);
toplevel = workspace()->findInternal(internalWindow);
} else {
toplevel = input()->findToplevel(pos);
}
@ -2394,7 +2395,7 @@ QWindow* InputDeviceHandler::findInternalWindow(const QPoint &pos) const
return nullptr;
}
const auto &internalClients = waylandServer()->internalClients();
const QList<InternalClient *> &internalClients = workspace()->internalClients();
if (internalClients.isEmpty()) {
return nullptr;
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2019 Martin Flöser <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -18,12 +19,14 @@ 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 "decorations/decorationbridge.h"
#include "deleted.h"
#include "workspace.h"
#include <KWayland/Client/surface.h>
#include <KWayland/Server/surface_interface.h>
#include <KDecoration2/Decoration>
#include <QOpenGLFramebufferObject>
#include <QWindow>
Q_DECLARE_METATYPE(NET::WindowType)
@ -32,58 +35,51 @@ static const QByteArray s_skipClosePropertyName = QByteArrayLiteral("KWIN_SKIP_C
namespace KWin
{
InternalClient::InternalClient(KWayland::Server::ShellSurfaceInterface *surface)
: ShellClient(surface)
InternalClient::InternalClient(QWindow *window)
: m_internalWindow(window)
, m_clientSize(window->size())
, m_windowId(window->winId())
, m_internalWindowFlags(window->flags())
{
findInternalWindow();
updateInternalWindowGeometry();
updateDecoration(true);
}
// Don't render the client until it provides a buffer.
ready_for_painting = false;
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::widthChanged, this, &InternalClient::updateInternalWindowGeometry);
connect(m_internalWindow, &QWindow::heightChanged, this, &InternalClient::updateInternalWindowGeometry);
connect(m_internalWindow, &QWindow::windowTitleChanged, this, &InternalClient::setCaption);
connect(m_internalWindow, &QWindow::opacityChanged, this, &InternalClient::setOpacity);
connect(m_internalWindow, &QWindow::destroyed, this, &InternalClient::destroyClient);
connect(this, &InternalClient::opacityChanged, this, &InternalClient::addRepaintFull);
const QVariant windowType = m_internalWindow->property("kwin_windowType");
if (!windowType.isNull()) {
m_windowType = windowType.value<NET::WindowType>();
}
setCaption(m_internalWindow->title());
setIcon(QIcon::fromTheme(QStringLiteral("kwin")));
setOnAllDesktops(true);
setOpacity(m_internalWindow->opacity());
// skip close animation support
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
m_internalWindow->installEventFilter(this);
return;
}
qCWarning(KWIN_CORE, "Couldn't find an internal window for surface with id %x", surface()->id());
setupCompositing();
updateColorScheme();
blockGeometryUpdates(true);
commitGeometry(m_internalWindow->geometry());
updateDecoration(true);
setGeometry(mapFromClient(m_internalWindow->geometry()));
setGeometryRestore(geometry());
blockGeometryUpdates(false);
m_internalWindow->installEventFilter(this);
}
InternalClient::~InternalClient()
{
}
bool InternalClient::eventFilter(QObject *watched, QEvent *event)
@ -101,6 +97,56 @@ bool InternalClient::eventFilter(QObject *watched, QEvent *event)
return false;
}
QStringList InternalClient::activities() const
{
return QStringList();
}
void InternalClient::blockActivityUpdates(bool b)
{
Q_UNUSED(b)
// Internal clients do not support activities.
}
qreal InternalClient::bufferScale() const
{
if (m_internalWindow) {
return m_internalWindow->devicePixelRatio();
}
return 1;
}
QString InternalClient::captionNormal() const
{
return m_captionNormal;
}
QString InternalClient::captionSuffix() const
{
return m_captionSuffix;
}
QPoint InternalClient::clientContentPos() const
{
return -1 * clientPos();
}
QSize InternalClient::clientSize() const
{
return m_clientSize;
}
void InternalClient::debug(QDebug &stream) const
{
stream.nospace() << "\'InternalClient:" << m_internalWindow << "\'";
}
QRect InternalClient::transparentRect() const
{
return QRect();
}
NET::WindowType InternalClient::windowType(bool direct, int supported_types) const
{
Q_UNUSED(direct)
@ -108,31 +154,39 @@ NET::WindowType InternalClient::windowType(bool direct, int supported_types) con
return m_windowType;
}
double InternalClient::opacity() const
{
return m_opacity;
}
void InternalClient::setOpacity(double opacity)
{
if (m_opacity == opacity) {
return;
}
const double oldOpacity = m_opacity;
m_opacity = opacity;
emit opacityChanged(this, oldOpacity);
}
void InternalClient::killWindow()
{
// we don't kill our internal windows
// We don't kill our internal windows.
}
bool InternalClient::isPopupWindow() const
{
if (Toplevel::isPopupWindow()) {
if (AbstractClient::isPopupWindow()) {
return true;
}
return m_internalWindowFlags.testFlag(Qt::Popup);
}
void InternalClient::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo)
QByteArray InternalClient::windowRole() const
{
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()));
return QByteArray();
}
void InternalClient::closeWindow()
@ -147,6 +201,16 @@ bool InternalClient::isCloseable() const
return true;
}
bool InternalClient::isFullScreenable() const
{
return false;
}
bool InternalClient::isFullScreen() const
{
return false;
}
bool InternalClient::isMaximizable() const
{
return false;
@ -174,7 +238,7 @@ bool InternalClient::isResizable() const
bool InternalClient::noBorder() const
{
return m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup);
return m_userNoBorder || m_internalWindowFlags.testFlag(Qt::FramelessWindowHint) || m_internalWindowFlags.testFlag(Qt::Popup);
}
bool InternalClient::userCanSetNoBorder() const
@ -187,11 +251,6 @@ bool InternalClient::wantsInput() const
return false;
}
bool InternalClient::acceptsFocus() const
{
return false;
}
bool InternalClient::isInternal() const
{
return true;
@ -226,75 +285,31 @@ quint32 InternalClient::windowId() const
return m_windowId;
}
void InternalClient::updateInternalWindowGeometry()
MaximizeMode InternalClient::maximizeMode() const
{
if (!m_internalWindow) {
return;
}
doSetGeometry(QRect(m_internalWindow->geometry().topLeft() - QPoint(borderLeft(), borderTop()),
m_internalWindow->geometry().size() + QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
return MaximizeRestore;
}
bool InternalClient::requestGeometry(const QRect &rect)
QRect InternalClient::geometryRestore() const
{
return m_maximizeRestoreGeometry;
}
bool InternalClient::isShown(bool shaded_is_shown) const
{
Q_UNUSED(shaded_is_shown)
return readyForPainting();
}
bool InternalClient::isHiddenInternal() const
{
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)
void InternalClient::hideClient(bool hide)
{
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));
}
Q_UNUSED(hide)
}
void InternalClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
@ -311,21 +326,46 @@ void InternalClient::resizeWithChecks(int w, int h, ForceGeometry_t force)
if (h > area.height()) {
h = area.height();
}
m_internalWindow->setGeometry(QRect(pos() + QPoint(borderLeft(), borderTop()), QSize(w, h) - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
setGeometry(QRect(x(), y(), w, h));
}
void InternalClient::doResizeSync()
void InternalClient::setGeometry(int x, int y, int w, int h, ForceGeometry_t force)
{
if (!m_internalWindow) {
const QRect rect(x, y, w, h);
if (areGeometryUpdatesBlocked()) {
geom = rect;
if (pendingGeometryUpdate() == PendingGeometryForced) {
// Maximum, nothing needed.
} else if (force == ForceGeometrySet) {
setPendingGeometryUpdate(PendingGeometryForced);
} else {
setPendingGeometryUpdate(PendingGeometryNormal);
}
return;
}
const auto rect = moveResizeGeometry();
m_internalWindow->setGeometry(QRect(rect.topLeft() + QPoint(borderLeft(), borderTop()), rect.size() - QSize(borderLeft() + borderRight(), borderTop() + borderBottom())));
if (pendingGeometryUpdate() != PendingGeometryNone) {
// Reset geometry to the one before blocking, so that we can compare properly.
geom = geometryBeforeUpdateBlocking();
}
if (geom == rect) {
return;
}
const QRect newClientGeometry = mapToClient(rect);
if (m_clientSize == newClientGeometry.size()) {
commitGeometry(rect);
} else {
requestGeometry(rect);
}
}
QWindow *InternalClient::internalWindow() const
void InternalClient::setGeometryRestore(const QRect &rect)
{
return m_internalWindow;
m_maximizeRestoreGeometry = rect;
}
bool InternalClient::supportsWindowRules() const
@ -333,4 +373,313 @@ bool InternalClient::supportsWindowRules() const
return false;
}
AbstractClient *InternalClient::findModal(bool allow_itself)
{
Q_UNUSED(allow_itself)
return nullptr;
}
void InternalClient::setOnAllActivities(bool set)
{
Q_UNUSED(set)
// Internal clients do not support activities.
}
void InternalClient::takeFocus()
{
}
bool InternalClient::userCanSetFullScreen() const
{
return false;
}
void InternalClient::setFullScreen(bool set, bool user)
{
Q_UNUSED(set)
Q_UNUSED(user)
}
void InternalClient::setNoBorder(bool set)
{
if (!userCanSetNoBorder()) {
return;
}
if (m_userNoBorder == set) {
return;
}
m_userNoBorder = set;
updateDecoration(true);
}
void InternalClient::updateDecoration(bool check_workspace_pos, bool force)
{
if (!force && isDecorated() == !noBorder()) {
return;
}
const QRect oldFrameGeometry = geometry();
const QRect oldClientGeometry = oldFrameGeometry - frameMargins();
GeometryUpdatesBlocker blocker(this);
if (force) {
destroyDecoration();
}
if (!noBorder()) {
createDecoration(oldClientGeometry);
} else {
destroyDecoration();
}
getShadow();
if (check_workspace_pos) {
checkWorkspacePosition(oldFrameGeometry, -2, oldClientGeometry);
}
}
void InternalClient::updateColorScheme()
{
AbstractClient::updateColorScheme(QString());
}
void InternalClient::showOnScreenEdge()
{
}
void InternalClient::destroyClient()
{
if (isMoveResize()) {
leaveMoveResize();
}
Deleted *deleted = Deleted::create(this);
emit windowClosed(this, deleted);
destroyDecoration();
workspace()->removeInternalClient(this);
deleted->unrefWindow();
m_internalWindow = nullptr;
delete this;
}
void InternalClient::present(const QSharedPointer<QOpenGLFramebufferObject> fbo)
{
Q_ASSERT(m_internalImage.isNull());
const QSize bufferSize = fbo->size() / bufferScale();
commitGeometry(QRect(pos(), sizeForClientSize(bufferSize)));
markAsMapped();
if (m_internalFBO != fbo) {
discardWindowPixmap();
m_internalFBO = fbo;
}
setDepth(32);
addDamageFull();
addRepaintFull();
}
void InternalClient::present(const QImage &image, const QRegion &damage)
{
Q_ASSERT(m_internalFBO.isNull());
const QSize bufferSize = image.size() / bufferScale();
commitGeometry(QRect(pos(), sizeForClientSize(bufferSize)));
markAsMapped();
if (m_internalImage.size() != image.size()) {
discardWindowPixmap();
}
m_internalImage = image;
setDepth(32);
addDamage(damage);
addRepaint(damage.translated(borderLeft(), borderTop()));
}
QWindow *InternalClient::internalWindow() const
{
return m_internalWindow;
}
bool InternalClient::acceptsFocus() const
{
return false;
}
bool InternalClient::belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const
{
Q_UNUSED(checks)
return qobject_cast<const InternalClient *>(other) != nullptr;
}
void InternalClient::changeMaximize(bool horizontal, bool vertical, bool adjust)
{
Q_UNUSED(horizontal)
Q_UNUSED(vertical)
Q_UNUSED(adjust)
// Internal clients are not maximizable.
}
void InternalClient::destroyDecoration()
{
if (!isDecorated()) {
return;
}
const QRect clientGeometry = mapToClient(geometry());
AbstractClient::destroyDecoration();
setGeometry(clientGeometry);
}
void InternalClient::doMove(int x, int y)
{
Q_UNUSED(x)
Q_UNUSED(y)
syncGeometryToInternalWindow();
}
void InternalClient::doResizeSync()
{
requestGeometry(moveResizeGeometry());
}
void InternalClient::updateCaption()
{
const QString oldSuffix = m_captionSuffix;
const auto shortcut = shortcutCaptionSuffix();
m_captionSuffix = shortcut;
if ((!isSpecialWindow() || isToolbar()) && findClientWithSameCaption()) {
int i = 2;
do {
m_captionSuffix = shortcut + QLatin1String(" <") + QString::number(i) + QLatin1Char('>');
i++;
} while (findClientWithSameCaption());
}
if (m_captionSuffix != oldSuffix) {
emit captionChanged();
}
}
QRect InternalClient::mapFromClient(const QRect &rect) const
{
return rect + frameMargins();
}
QRect InternalClient::mapToClient(const QRect &rect) const
{
return rect - frameMargins();
}
void InternalClient::createDecoration(const QRect &rect)
{
KDecoration2::Decoration *decoration = Decoration::DecorationBridge::self()->createDecoration(this);
if (decoration) {
QMetaObject::invokeMethod(decoration, "update", Qt::QueuedConnection);
connect(decoration, &KDecoration2::Decoration::shadowChanged, this, &Toplevel::getShadow);
connect(decoration, &KDecoration2::Decoration::bordersChanged, this,
[this]() {
GeometryUpdatesBlocker blocker(this);
const QRect oldGeometry = geometry();
if (!isShade()) {
checkWorkspacePosition(oldGeometry);
}
emit geometryShapeChanged(this, oldGeometry);
}
);
}
const QRect oldFrameGeometry = geometry();
setDecoration(decoration);
setGeometry(mapFromClient(rect));
emit geometryShapeChanged(this, oldFrameGeometry);
}
void InternalClient::requestGeometry(const QRect &rect)
{
if (m_internalWindow) {
m_internalWindow->setGeometry(mapToClient(rect));
}
}
void InternalClient::commitGeometry(const QRect &rect)
{
if (geom == rect && pendingGeometryUpdate() == PendingGeometryNone) {
return;
}
geom = rect;
m_clientSize = mapToClient(geometry()).size();
addWorkspaceRepaint(visibleRect());
syncGeometryToInternalWindow();
const QRect oldGeometry = geometryBeforeUpdateBlocking();
updateGeometryBeforeUpdateBlocking();
emit geometryShapeChanged(this, oldGeometry);
if (isResize()) {
performMoveResize();
}
}
void InternalClient::setCaption(const QString &caption)
{
if (m_captionNormal == caption) {
return;
}
m_captionNormal = caption;
const QString oldCaptionSuffix = m_captionSuffix;
updateCaption();
if (m_captionSuffix == oldCaptionSuffix) {
emit captionChanged();
}
}
void InternalClient::markAsMapped()
{
if (!ready_for_painting) {
setReadyForPainting();
workspace()->addInternalClient(this);
}
}
void InternalClient::syncGeometryToInternalWindow()
{
if (m_internalWindow->geometry() == mapToClient(geometry())) {
return;
}
QTimer::singleShot(0, this, [this] { requestGeometry(geometry()); });
}
void InternalClient::updateInternalWindowGeometry()
{
if (isMoveResize()) {
return;
}
commitGeometry(mapFromClient(m_internalWindow->geometry()));
}
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2019 Martin Flöser <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -19,31 +20,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#pragma once
#include "shell_client.h"
#include "abstract_client.h"
namespace KWin
{
class KWIN_EXPORT InternalClient : public ShellClient
class KWIN_EXPORT InternalClient : public AbstractClient
{
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);
explicit InternalClient(QWindow *window);
~InternalClient() override;
bool eventFilter(QObject *watched, QEvent *event) override;
QStringList activities() const override;
void blockActivityUpdates(bool b = true) override;
qreal bufferScale() const override;
QString captionNormal() const override;
QString captionSuffix() const override;
QPoint clientContentPos() const override;
QSize clientSize() const override;
void debug(QDebug &stream) const override;
QRect transparentRect() const override;
NET::WindowType windowType(bool direct = false, int supported_types = 0) const override;
double opacity() const override;
void setOpacity(double opacity) override;
void killWindow() override;
bool isPopupWindow() const override;
void setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo) override;
QByteArray windowRole() const override;
void closeWindow() override;
bool isCloseable() const override;
bool isFullScreenable() const override;
bool isFullScreen() const override;
bool isMaximizable() const override;
bool isMinimizable() const override;
bool isMovable() const override;
@ -57,27 +67,64 @@ public:
bool isInputMethod() const override;
bool isOutline() const override;
quint32 windowId() const override;
MaximizeMode maximizeMode() const override;
QRect geometryRestore() const override;
bool isShown(bool shaded_is_shown) const override;
bool isHiddenInternal() const override;
void hideClient(bool hide) override;
using AbstractClient::resizeWithChecks;
void resizeWithChecks(int w, int h, ForceGeometry_t force = NormalGeometrySet) override;
QWindow *internalWindow() const override;
using AbstractClient::setGeometry;
void setGeometry(int x, int y, int w, int h, ForceGeometry_t force = NormalGeometrySet) override;
void setGeometryRestore(const QRect &rect) override;
bool supportsWindowRules() const override;
AbstractClient *findModal(bool allow_itself = false) override;
void setOnAllActivities(bool set) override;
void takeFocus() override;
bool userCanSetFullScreen() const override;
void setFullScreen(bool set, bool user = true) override;
void setNoBorder(bool set) override;
void updateDecoration(bool check_workspace_pos, bool force = false) override;
void updateColorScheme() override;
void showOnScreenEdge() override;
void destroyClient();
void present(const QSharedPointer<QOpenGLFramebufferObject> fbo);
void present(const QImage &image, const QRegion &damage);
QWindow *internalWindow() const;
protected:
bool acceptsFocus() const override;
bool belongsToSameApplication(const AbstractClient *other, SameApplicationChecks checks) const override;
void changeMaximize(bool horizontal, bool vertical, bool adjust) override;
void destroyDecoration() override;
void doMove(int x, int y) override;
void doResizeSync() override;
bool requestGeometry(const QRect &rect) override;
void doSetGeometry(const QRect &rect) override;
void updateCaption() override;
private:
void findInternalWindow();
void updateInternalWindowGeometry();
QRect mapFromClient(const QRect &rect) const;
QRect mapToClient(const QRect &rect) const;
void createDecoration(const QRect &rect);
void requestGeometry(const QRect &rect);
void commitGeometry(const QRect &rect);
void setCaption(const QString &caption);
void markAsMapped();
void syncGeometryToInternalWindow();
void updateInternalWindowGeometry();
QWindow *m_internalWindow = nullptr;
QRect m_maximizeRestoreGeometry;
QSize m_clientSize = QSize(0, 0);
QString m_captionNormal;
QString m_captionSuffix;
double m_opacity = 1.0;
NET::WindowType m_windowType = NET::Normal;
quint32 m_windowId = 0;
QWindow *m_internalWindow = nullptr;
Qt::WindowFlags m_internalWindowFlags = Qt::WindowFlags();
bool m_userNoBorder = false;
Q_DISABLE_COPY(InternalClient)
};
}

View file

@ -95,6 +95,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "screenedge.h"
#include "shell_client.h"
#include "wayland_server.h"
#include "internal_client.h"
#include <QDebug>
@ -761,14 +762,13 @@ void Workspace::updateXStackingOrder()
}
}
}
if (waylandServer()) {
const auto clients = waylandServer()->internalClients();
for (auto c: clients) {
if (c->isShown(false)) {
x_stacking << c;
}
for (InternalClient *client : workspace()->internalClients()) {
if (client->isShown(false)) {
x_stacking.append(client);
}
}
m_xStackingDirty = false;
}

View file

@ -344,11 +344,16 @@ OpenGLBackend *AbstractEglTexture::backend()
bool AbstractEglTexture::loadTexture(WindowPixmap *pixmap)
{
// FIXME: Refactor this method.
const auto &buffer = pixmap->buffer();
if (buffer.isNull()) {
if (updateFromFBO(pixmap->fbo())) {
return true;
}
if (loadInternalImageObject(pixmap)) {
return true;
}
return false;
}
// try Wayland loading
@ -365,13 +370,14 @@ bool AbstractEglTexture::loadTexture(WindowPixmap *pixmap)
void AbstractEglTexture::updateTexture(WindowPixmap *pixmap)
{
// FIXME: Refactor this method.
const auto &buffer = pixmap->buffer();
if (buffer.isNull()) {
const auto &fbo = pixmap->fbo();
if (!fbo.isNull()) {
if (m_texture != fbo->texture()) {
updateFromFBO(fbo);
if (updateFromFBO(pixmap->fbo())) {
return;
}
if (updateFromInternalImageObject(pixmap)) {
return;
}
return;
@ -554,6 +560,58 @@ bool AbstractEglTexture::loadDmabufTexture(const QPointer< KWayland::Server::Buf
return true;
}
bool AbstractEglTexture::loadInternalImageObject(WindowPixmap *pixmap)
{
// FIXME: Share some code with loadShmTexture().
const QImage image = pixmap->internalImage();
if (image.isNull()) {
return false;
}
glGenTextures(1, &m_texture);
q->setFilter(GL_LINEAR);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setYInverted(true);
q->bind();
const QSize &size = image.size();
// TODO: this should be shared with GLTexture(const QImage&, GLenum)
GLenum format = 0;
switch (image.format()) {
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
format = GL_RGBA8;
break;
case QImage::Format_RGB32:
format = GL_RGB8;
break;
default:
return false;
}
if (GLPlatform::instance()->isGLES()) {
if (s_supportsARGB32 && format == GL_RGBA8) {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
glTexImage2D(m_target, 0, GL_BGRA_EXT, im.width(), im.height(),
0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.bits());
} else {
const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
glTexImage2D(m_target, 0, GL_RGBA, im.width(), im.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, im.bits());
}
} else {
glTexImage2D(m_target, 0, format, size.width(), size.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
}
q->unbind();
m_size = size;
updateMatrix();
return true;
}
EGLImageKHR AbstractEglTexture::attach(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
EGLint format, yInverted;
@ -596,5 +654,55 @@ bool AbstractEglTexture::updateFromFBO(const QSharedPointer<QOpenGLFramebufferOb
return true;
}
bool AbstractEglTexture::updateFromInternalImageObject(WindowPixmap *pixmap)
{
// FIXME: Share some code with the shm fallback in updateTexture().
const QImage image = pixmap->internalImage();
if (image.isNull()) {
return false;
}
if (m_size != image.size()) {
glDeleteTextures(1, &m_texture);
return loadInternalImageObject(pixmap);
}
const QRegion damage = pixmap->toplevel()->damage();
const qreal scale = image.devicePixelRatio();
q->bind();
// TODO: this should be shared with GLTexture::update
if (GLPlatform::instance()->isGLES()) {
if (s_supportsARGB32 && (image.format() == QImage::Format_ARGB32 || image.format() == QImage::Format_ARGB32_Premultiplied)) {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage) {
auto scaledRect = QRect(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale);
glTexSubImage2D(m_target, 0, scaledRect.x(), scaledRect.y(), scaledRect.width(), scaledRect.height(),
GL_BGRA_EXT, GL_UNSIGNED_BYTE, im.copy(scaledRect).bits());
}
} else {
const QImage im = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
for (const QRect &rect : damage) {
auto scaledRect = QRect(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale);
glTexSubImage2D(m_target, 0, scaledRect.x(), scaledRect.y(), scaledRect.width(), scaledRect.height(),
GL_RGBA, GL_UNSIGNED_BYTE, im.copy(scaledRect).bits());
}
}
} else {
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage) {
auto scaledRect = QRect(rect.x() * scale, rect.y() * scale, rect.width() * scale, rect.height() * scale);
glTexSubImage2D(m_target, 0, scaledRect.x(), scaledRect.y(), scaledRect.width(), scaledRect.height(),
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(scaledRect).bits());
}
}
q->unbind();
return true;
}
}

View file

@ -111,8 +111,10 @@ private:
bool loadShmTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
bool loadEglTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
bool loadDmabufTexture(const QPointer< KWayland::Server::BufferInterface > &buffer);
bool loadInternalImageObject(WindowPixmap *pixmap);
EGLImageKHR attach(const QPointer<KWayland::Server::BufferInterface> &buffer);
bool updateFromFBO(const QSharedPointer<QOpenGLFramebufferObject> &fbo);
bool updateFromInternalImageObject(WindowPixmap *pixmap);
SceneOpenGLTexture *q;
AbstractEglBackend *m_backend;
EGLImageKHR m_image;

View file

@ -7,7 +7,6 @@ set(QPA_SOURCES
eglhelpers.cpp
integration.cpp
main.cpp
nativeinterface.cpp
offscreensurface.cpp
platformcursor.cpp
screen.cpp
@ -31,7 +30,6 @@ target_link_libraries(KWinQpaPlugin
${QT5PLATFORMSUPPORT_LIBS}
${FREETYPE_LIBRARIES} # Must be after QT5PLATFORMSUPPORT_LIBS
Fontconfig::Fontconfig
KF5::WaylandClient
kwin
)

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -17,39 +18,19 @@ 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 "window.h"
#include "backingstore.h"
#include "../../wayland_server.h"
#include "window.h"
#include <KWayland/Client/buffer.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/surface.h>
#include "internal_client.h"
namespace KWin
{
namespace QPA
{
BackingStore::BackingStore(QWindow *w, KWayland::Client::ShmPool *shm)
: QPlatformBackingStore(w)
, m_shm(shm)
, m_backBuffer(QSize(), QImage::Format_ARGB32_Premultiplied)
BackingStore::BackingStore(QWindow *window)
: QPlatformBackingStore(window)
{
QObject::connect(m_shm, &KWayland::Client::ShmPool::poolResized,
[this] {
if (!m_buffer) {
return;
}
auto b = m_buffer.toStrongRef();
if (!b->isUsed()){
return;
}
const QSize size = m_backBuffer.size();
m_backBuffer = QImage(b->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
m_backBuffer.setDevicePixelRatio(scale());
}
);
}
BackingStore::~BackingStore() = default;
@ -62,66 +43,60 @@ QPaintDevice *BackingStore::paintDevice()
void BackingStore::resize(const QSize &size, const QRegion &staticContents)
{
Q_UNUSED(staticContents)
m_size = size * scale();
if (!m_buffer) {
if (m_backBuffer.size() == size) {
return;
}
m_buffer.toStrongRef()->setUsed(false);
m_buffer.clear();
const QPlatformWindow *platformWindow = static_cast<QPlatformWindow *>(window()->handle());
const qreal devicePixelRatio = platformWindow->devicePixelRatio();
m_backBuffer = QImage(size * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
m_backBuffer.setDevicePixelRatio(devicePixelRatio);
m_frontBuffer = QImage(size * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
m_frontBuffer.setDevicePixelRatio(devicePixelRatio);
}
static void blitImage(const QImage &source, QImage &target, const QRect &rect)
{
Q_ASSERT(source.format() == QImage::Format_ARGB32_Premultiplied);
Q_ASSERT(target.format() == QImage::Format_ARGB32_Premultiplied);
const int devicePixelRatio = target.devicePixelRatio();
const int x = rect.x() * devicePixelRatio;
const int y = rect.y() * devicePixelRatio;
const int width = rect.width() * devicePixelRatio;
const int height = rect.height() * devicePixelRatio;
for (int i = y; i < y + height; ++i) {
const uint32_t *in = reinterpret_cast<const uint32_t *>(source.scanLine(i));
uint32_t *out = reinterpret_cast<uint32_t *>(target.scanLine(i));
std::copy(in + x, in + x + width, out + x);
}
}
static void blitImage(const QImage &source, QImage &target, const QRegion &region)
{
for (const QRect &rect : region) {
blitImage(source, target, rect);
}
}
void BackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
Q_UNUSED(region)
Q_UNUSED(offset)
auto w = static_cast<Window *>(window->handle());
auto s = w->surface();
if (!s) {
Window *platformWindow = static_cast<Window *>(window->handle());
InternalClient *client = platformWindow->client();
if (!client) {
return;
}
s->attachBuffer(m_buffer);
// TODO: proper damage region
s->damage(QRect(QPoint(0, 0), m_backBuffer.size() / scale()));
s->commit(KWayland::Client::Surface::CommitFlag::None);
waylandServer()->internalClientConection()->flush();
waylandServer()->dispatch();
}
void BackingStore::beginPaint(const QRegion&)
{
if (m_buffer) {
auto b = m_buffer.toStrongRef();
if (b->isReleased()) {
// we can re-use this buffer
b->setReleased(false);
return;
} else {
// buffer is still in use, get a new one
b->setUsed(false);
}
}
auto oldBuffer = m_buffer.toStrongRef();
m_buffer.clear();
m_buffer = m_shm->getBuffer(m_size, m_size.width() * 4);
if (!m_buffer) {
m_backBuffer = QImage();
return;
}
auto b = m_buffer.toStrongRef();
b->setUsed(true);
m_backBuffer = QImage(b->address(), m_size.width(), m_size.height(), QImage::Format_ARGB32_Premultiplied);
m_backBuffer.setDevicePixelRatio(scale());
if (oldBuffer) {
b->copy(oldBuffer->address());
} else {
m_backBuffer.fill(Qt::transparent);
}
}
blitImage(m_backBuffer, m_frontBuffer, region);
int BackingStore::scale() const
{
return static_cast<Window *>(window()->handle())->scale();
client->present(m_frontBuffer, region);
}
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -22,15 +23,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <qpa/qplatformbackingstore.h>
namespace KWayland
{
namespace Client
{
class Buffer;
class ShmPool;
}
}
namespace KWin
{
namespace QPA
@ -39,20 +31,16 @@ namespace QPA
class BackingStore : public QPlatformBackingStore
{
public:
explicit BackingStore(QWindow *w, KWayland::Client::ShmPool *shm);
explicit BackingStore(QWindow *window);
~BackingStore() override;
QPaintDevice *paintDevice() override;
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
void resize(const QSize &size, const QRegion &staticContents) override;
void beginPaint(const QRegion &) override;
private:
int scale() const;
KWayland::Client::ShmPool *m_shm;
QWeakPointer<KWayland::Client::Buffer> m_buffer;
QImage m_backBuffer;
QSize m_size;
QImage m_frontBuffer;
};
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -19,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "integration.h"
#include "backingstore.h"
#include "nativeinterface.h"
#include "offscreensurface.h"
#include "screen.h"
#include "sharingplatformcontext.h"
@ -28,14 +28,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "../../platform.h"
#include "../../screens.h"
#include "../../virtualkeyboard.h"
#include "../../wayland_server.h"
#include <KWayland/Client/compositor.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/registry.h>
#include <KWayland/Client/shell.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Server/clientconnection.h>
#include <QCoreApplication>
#include <QtConcurrentRun>
@ -59,7 +51,6 @@ Integration::Integration()
: QObject()
, QPlatformIntegration()
, m_fontDb(new QGenericUnixFontDatabase())
, m_nativeInterface(new NativeInterface(this))
, m_inputContext()
{
}
@ -139,25 +130,12 @@ QAbstractEventDispatcher *Integration::createEventDispatcher() const
QPlatformBackingStore *Integration::createPlatformBackingStore(QWindow *window) const
{
auto registry = waylandServer()->internalClientRegistry();
const auto shm = registry->interface(KWayland::Client::Registry::Interface::Shm);
if (shm.name == 0u) {
return nullptr;
}
return new BackingStore(window, registry->createShmPool(shm.name, shm.version, window));
return new BackingStore(window);
}
QPlatformWindow *Integration::createPlatformWindow(QWindow *window) const
{
auto c = compositor();
auto s = shell();
if (!s || !c) {
return new QPlatformWindow(window);
} else {
// don't set window as parent, cause infinite recursion in PlasmaQuick::Dialog
auto surface = c->createSurface(c);
return new Window(window, surface, s->createSurface(surface, surface), this);
}
return new Window(window);
}
QPlatformOffscreenSurface *Integration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
@ -183,11 +161,6 @@ QStringList Integration::themeNames() const
return QStringList({QLatin1String(QGenericUnixTheme::name)});
}
QPlatformNativeInterface *Integration::nativeInterface() const
{
return m_nativeInterface;
}
QPlatformOpenGLContext *Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
if (kwinApp()->platform()->supportsQpaContext()) {
@ -235,37 +208,6 @@ void Integration::initScreens()
m_screens = newScreens;
}
KWayland::Client::Compositor *Integration::compositor() const
{
if (!m_compositor) {
using namespace KWayland::Client;
auto registry = waylandServer()->internalClientRegistry();
const auto c = registry->interface(Registry::Interface::Compositor);
if (c.name != 0u) {
const_cast<Integration*>(this)->m_compositor = registry->createCompositor(c.name, c.version, registry);
}
}
return m_compositor;
}
KWayland::Client::Shell *Integration::shell() const
{
if (!m_shell) {
using namespace KWayland::Client;
auto registry = waylandServer()->internalClientRegistry();
const auto s = registry->interface(Registry::Interface::Shell);
if (s.name != 0u) {
const_cast<Integration*>(this)->m_shell = registry->createShell(s.name, s.version, registry);
}
}
return m_shell;
}
EGLDisplay Integration::eglDisplay() const
{
return m_eglDisplay;
}
QPlatformInputContext *Integration::inputContext() const
{
return m_inputContext.data();

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -27,15 +28,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <qpa/qplatformintegration.h>
#include <QObject>
namespace KWayland
{
namespace Client
{
class Compositor;
class Shell;
}
}
namespace KWin
{
namespace QPA
@ -58,24 +50,16 @@ public:
QPlatformFontDatabase *fontDatabase() const override;
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
QPlatformNativeInterface *nativeInterface() const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
void initialize() override;
QPlatformInputContext *inputContext() const override;
KWayland::Client::Compositor *compositor() const;
EGLDisplay eglDisplay() const;
void initialize() override;
private:
void initScreens();
KWayland::Client::Shell *shell() const;
QPlatformFontDatabase *m_fontDb;
QPlatformNativeInterface *m_nativeInterface;
KWayland::Client::Compositor *m_compositor = nullptr;
KWayland::Client::Shell *m_shell = nullptr;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
Screen *m_dummyScreen = nullptr;
QScopedPointer<QPlatformInputContext> m_inputContext;
QVector<Screen*> m_screens;

View file

@ -1,106 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <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 "nativeinterface.h"
#include "integration.h"
#include "window.h"
#include "../../wayland_server.h"
#include <KWayland/Client/compositor.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/surface.h>
#include <QWindow>
namespace KWin
{
namespace QPA
{
static const QByteArray s_displayKey = QByteArrayLiteral("display");
static const QByteArray s_wlDisplayKey = QByteArrayLiteral("wl_display");
static const QByteArray s_compositorKey = QByteArrayLiteral("compositor");
static const QByteArray s_surfaceKey = QByteArrayLiteral("surface");
NativeInterface::NativeInterface(Integration *integration)
: QPlatformNativeInterface()
, m_integration(integration)
{
}
void *NativeInterface::nativeResourceForIntegration(const QByteArray &resource)
{
const QByteArray r = resource.toLower();
if (r == s_displayKey || r == s_wlDisplayKey) {
if (!waylandServer() || !waylandServer()->internalClientConection()) {
return nullptr;
}
return waylandServer()->internalClientConection()->display();
}
if (r == s_compositorKey) {
return static_cast<wl_compositor*>(*m_integration->compositor());
}
return nullptr;
}
void *NativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
{
const QByteArray r = resource.toLower();
if (r == s_displayKey || r == s_wlDisplayKey) {
if (!waylandServer() || !waylandServer()->internalClientConection()) {
return nullptr;
}
return waylandServer()->internalClientConection()->display();
}
if (r == s_compositorKey) {
return static_cast<wl_compositor*>(*m_integration->compositor());
}
if (r == s_surfaceKey && window) {
if (auto handle = window->handle()) {
if (auto surface = static_cast<Window*>(handle)->surface()) {
return static_cast<wl_surface*>(*surface);
}
}
}
return nullptr;
}
static void roundtrip()
{
if (!waylandServer()) {
return;
}
auto c = waylandServer()->internalClientConection();
if (!c) {
return;
}
c->flush();
waylandServer()->dispatch();
}
QFunctionPointer NativeInterface::platformFunction(const QByteArray &function) const
{
if (qstrcmp(function.toLower(), "roundtrip") == 0) {
return &roundtrip;
}
return nullptr;
}
}
}

View file

@ -1,47 +0,0 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <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/>.
*********************************************************************/
#ifndef KWIN_QPA_NATIVEINTERFACE_H
#define KWIN_QPA_NATIVEINTERFACE_H
#include <qpa/qplatformnativeinterface.h>
namespace KWin
{
namespace QPA
{
class Integration;
class NativeInterface : public QPlatformNativeInterface
{
public:
explicit NativeInterface(Integration *integration);
void *nativeResourceForIntegration(const QByteArray &resource) override;
void *nativeResourceForWindow(const QByteArray &resourceString, QWindow *window) override;
QFunctionPointer platformFunction(const QByteArray &function) const override;
private:
Integration *m_integration;
};
}
}
#endif

View file

@ -20,8 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "sharingplatformcontext.h"
#include "offscreensurface.h"
#include "window.h"
#include "../../internal_client.h"
#include "../../main.h"
#include "../../platform.h"
#include "../../shell_client.h"
#include <logging.h>
#include <QOpenGLFramebufferObject>
@ -82,14 +85,13 @@ void SharingPlatformContext::swapBuffers(QPlatformSurface *surface)
{
if (surface->surface()->surfaceClass() == QSurface::Window) {
Window *window = static_cast<Window *>(surface);
auto c = window->shellClient();
if (!c) {
qCDebug(KWIN_QPA) << "SwapBuffers called but there is no ShellClient";
InternalClient *client = window->client();
if (!client) {
return;
}
context()->makeCurrent(surface->surface());
glFlush();
c->setInternalFramebufferObject(window->swapFBO());
client->present(window->swapFBO());
window->bindContentFBO();
}
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -18,58 +19,41 @@ 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 "window.h"
#include "integration.h"
#include "screens.h"
#include "../../shell_client.h"
#include "../../wayland_server.h"
#include "internal_client.h"
#include <logging.h>
#include <QOpenGLFramebufferObject>
#include <qpa/qwindowsysteminterface.h>
#include <KWayland/Client/buffer.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/shell.h>
#include <KWayland/Client/surface.h>
namespace KWin
{
namespace QPA
{
static quint32 s_windowId = 0;
Window::Window(QWindow *window, KWayland::Client::Surface *surface, KWayland::Client::ShellSurface *shellSurface, const Integration *integration)
Window::Window(QWindow *window)
: QPlatformWindow(window)
, m_surface(surface)
, m_shellSurface(shellSurface)
, m_windowId(++s_windowId)
, m_integration(integration)
, m_scale(screens()->maxScale())
{
m_surface->setScale(m_scale);
QObject::connect(m_surface, &QObject::destroyed, window, [this] { m_surface = nullptr;});
QObject::connect(m_shellSurface, &QObject::destroyed, window, [this] { m_shellSurface = nullptr;});
waylandServer()->internalClientConection()->flush();
}
Window::~Window()
{
unmap();
delete m_shellSurface;
delete m_surface;
}
WId Window::winId() const
{
return m_windowId;
}
void Window::setVisible(bool visible)
{
if (!visible) {
if (visible) {
map();
} else {
unmap();
}
QPlatformWindow::setVisible(visible);
}
@ -100,18 +84,14 @@ void Window::setGeometry(const QRect &rect)
QWindowSystemInterface::handleGeometryChange(window(), geometry());
}
void Window::unmap()
WId Window::winId() const
{
if (m_shellClient) {
m_shellClient->setInternalFramebufferObject(QSharedPointer<QOpenGLFramebufferObject>());
}
if (m_surface) {
m_surface->attachBuffer(KWayland::Client::Buffer::Ptr());
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
}
if (waylandServer()->internalClientConection()) {
waylandServer()->internalClientConection()->flush();
}
return m_windowId;
}
qreal Window::devicePixelRatio() const
{
return m_scale;
}
void Window::bindContentFBO()
@ -122,14 +102,23 @@ void Window::bindContentFBO()
m_contentFBO->bind();
}
const QSharedPointer<QOpenGLFramebufferObject> &Window::contentFBO() const
{
return m_contentFBO;
}
QSharedPointer<QOpenGLFramebufferObject> Window::swapFBO()
{
auto fbo = m_contentFBO;
QSharedPointer<QOpenGLFramebufferObject> fbo = m_contentFBO;
m_contentFBO.clear();
m_surface->commit(KWayland::Client::Surface::CommitFlag::None);
return fbo;
}
InternalClient *Window::client() const
{
return m_handle;
}
void Window::createFBO()
{
const QRect &r = geometry();
@ -144,23 +133,25 @@ void Window::createFBO()
m_resized = false;
}
ShellClient *Window::shellClient()
void Window::map()
{
if (!m_shellClient) {
waylandServer()->dispatch();
m_shellClient = waylandServer()->findClient(window());
if (m_handle) {
return;
}
return m_shellClient;
m_handle = new InternalClient(window());
}
int Window::scale() const
void Window::unmap()
{
return m_scale;
}
if (!m_handle) {
return;
}
qreal Window::devicePixelRatio() const
{
return m_scale;
m_handle->destroyClient();
m_handle = nullptr;
m_contentFBO = nullptr;
}
}

View file

@ -3,6 +3,7 @@
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -20,69 +21,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_QPA_WINDOW_H
#define KWIN_QPA_WINDOW_H
#include <epoxy/egl.h>
#include "fixqopengl.h"
#include <fixx11h.h>
#include <qpa/qplatformwindow.h>
class QOpenGLFramebufferObject;
namespace KWayland
{
namespace Client
{
class Surface;
class ShellSurface;
}
}
namespace KWin
{
class ShellClient;
class InternalClient;
namespace QPA
{
class Integration;
class Window : public QPlatformWindow
{
public:
explicit Window(QWindow *window, KWayland::Client::Surface *surface, KWayland::Client::ShellSurface *shellSurface, const Integration *integration);
explicit Window(QWindow *window);
~Window() override;
void setVisible(bool visible) override;
void setGeometry(const QRect &rect) override;
WId winId() const override;
KWayland::Client::Surface *surface() const {
return m_surface;
}
int scale() const;
qreal devicePixelRatio() const override;
void bindContentFBO();
const QSharedPointer<QOpenGLFramebufferObject> &contentFBO() const {
return m_contentFBO;
}
const QSharedPointer<QOpenGLFramebufferObject> &contentFBO() const;
QSharedPointer<QOpenGLFramebufferObject> swapFBO();
ShellClient *shellClient();
InternalClient *client() const;
private:
void unmap();
void createFBO();
void map();
void unmap();
KWayland::Client::Surface *m_surface;
KWayland::Client::ShellSurface *m_shellSurface;
InternalClient *m_handle = nullptr;
QSharedPointer<QOpenGLFramebufferObject> m_contentFBO;
bool m_resized = false;
ShellClient *m_shellClient = nullptr;
quint32 m_windowId;
const Integration *m_integration;
bool m_resized = false;
int m_scale = 1;
};

View file

@ -1534,6 +1534,27 @@ OpenGLWindowPixmap::~OpenGLWindowPixmap()
{
}
static bool needsPixmapUpdate(const OpenGLWindowPixmap *pixmap)
{
// That's a regular Wayland client.
if (pixmap->surface()) {
return !pixmap->surface()->trackedDamage().isEmpty();
}
// That's an internal client with a raster buffer attached.
if (!pixmap->internalImage().isNull()) {
return !pixmap->toplevel()->damage().isEmpty();
}
// That's an internal client with an opengl framebuffer object attached.
if (!pixmap->fbo().isNull()) {
return !pixmap->toplevel()->damage().isEmpty();
}
// That's an X11 client.
return false;
}
bool OpenGLWindowPixmap::bind()
{
if (!m_texture->isNull()) {
@ -1541,8 +1562,7 @@ bool OpenGLWindowPixmap::bind()
if (subSurface().isNull() && !toplevel()->damage().isEmpty()) {
updateBuffer();
}
auto s = surface();
if (s && !s->trackedDamage().isEmpty()) {
if (needsPixmapUpdate(this)) {
m_texture->updateFromPixmap(this);
// mipmaps need to be updated
m_texture->setDirty();

View file

@ -402,6 +402,11 @@ void QPainterWindowPixmap::create()
if (!isValid()) {
return;
}
if (!surface()) {
// That's an internal client.
m_image = internalImage();
return;
}
// performing deep copy, this could probably be improved
m_image = buffer()->data().copy();
if (auto s = surface()) {
@ -419,6 +424,11 @@ void QPainterWindowPixmap::updateBuffer()
const auto oldBuffer = buffer();
WindowPixmap::updateBuffer();
const auto &b = buffer();
if (!surface()) {
// That's an internal client.
m_image = internalImage();
return;
}
if (b.isNull()) {
m_image = QImage();
return;

View file

@ -474,7 +474,6 @@ void PointerInputRedirection::cleanupInternalWindow(QWindow *old, QWindow *now)
if (old) {
// leave internal window
// TODO: do this instead via Wayland protocol as below
QEvent leaveEvent(QEvent::Leave);
QCoreApplication::sendEvent(old, &leaveEvent);
}
@ -548,22 +547,22 @@ void PointerInputRedirection::focusUpdate(Toplevel *focusOld, Toplevel *focusNow
workspace()->updateFocusMousePosition(m_pos.toPoint());
}
auto seat = waylandServer()->seat();
if (!focusNow || !focusNow->surface() || decoration()) {
// no new surface or internal window or on decoration -> cleanup
warpXcbOnSurfaceLeft(nullptr);
seat->setFocusedPointerSurface(nullptr);
return;
}
if (internalWindow()) {
// enter internal window
// TODO: do this instead via Wayland protocol as below
const auto pos = at()->pos();
QEnterEvent enterEvent(pos, pos, m_pos);
QCoreApplication::sendEvent(internalWindow().data(), &enterEvent);
}
auto seat = waylandServer()->seat();
if (!focusNow || !focusNow->surface() || decoration()) {
// Clean up focused pointer surface if there's no client to take focus,
// or the pointer is on a client without surface or on a decoration.
warpXcbOnSurfaceLeft(nullptr);
seat->setFocusedPointerSurface(nullptr);
return;
}
// TODO: add convenient API to update global pos together with updating focused surface
warpXcbOnSurfaceLeft(focusNow->surface());

View file

@ -844,10 +844,8 @@ WindowQuadList Scene::Window::buildQuads(bool force) const
if (cached_quad_list != nullptr && !force)
return *cached_quad_list;
WindowQuadList ret;
qreal scale = 1.0;
if (toplevel->surface()) {
scale = toplevel->surface()->scale();
}
const qreal scale = toplevel->bufferScale();
if (toplevel->clientPos() == QPoint(0, 0) && toplevel->clientSize() == toplevel->decorationRect().size())
ret = makeQuads(WindowQuadContents, shape(), QPoint(0,0), scale); // has no decoration
@ -1059,7 +1057,7 @@ WindowPixmap *WindowPixmap::createChild(const QPointer<KWayland::Server::SubSurf
bool WindowPixmap::isValid() const
{
if (!m_buffer.isNull() || !m_fbo.isNull()) {
if (!m_buffer.isNull() || !m_fbo.isNull() || !m_internalImage.isNull()) {
return true;
}
return m_pixmap != XCB_PIXMAP_NONE;
@ -1110,13 +1108,11 @@ void WindowPixmap::updateBuffer()
m_buffer->unref();
m_buffer.clear();
}
} else {
// might be an internal window
const auto &fbo = toplevel()->internalFramebufferObject();
if (!fbo.isNull()) {
m_fbo = fbo;
}
}
} else if (toplevel()->internalFramebufferObject()) {
m_fbo = toplevel()->internalFramebufferObject();
} else if (!toplevel()->internalImageObject().isNull()) {
m_internalImage = toplevel()->internalImageObject();
} else {
if (m_buffer) {
QObject::disconnect(m_buffer.data(), &BufferInterface::aboutToBeDestroyed, m_buffer.data(), &BufferInterface::unref);

View file

@ -425,6 +425,7 @@ public:
*/
QPointer<KWayland::Server::BufferInterface> buffer() const;
const QSharedPointer<QOpenGLFramebufferObject> &fbo() const;
QImage internalImage() const;
/**
* @brief Whether this WindowPixmap is considered as discarded. This means the window has changed in a way that a new
* WindowPixmap should have been created already.
@ -512,6 +513,7 @@ private:
QRect m_contentsRect;
QPointer<KWayland::Server::BufferInterface> m_buffer;
QSharedPointer<QOpenGLFramebufferObject> m_fbo;
QImage m_internalImage;
WindowPixmap *m_parent = nullptr;
QVector<WindowPixmap*> m_children;
QPointer<KWayland::Server::SubSurfaceInterface> m_subSurface;
@ -618,6 +620,12 @@ const QSharedPointer<QOpenGLFramebufferObject> &WindowPixmap::fbo() const
return m_fbo;
}
inline
QImage WindowPixmap::internalImage() const
{
return m_internalImage;
}
template <typename T>
inline
T* Scene::Window::windowPixmap()

View file

@ -4,6 +4,7 @@
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2018 David Edmundson <davidedmundson@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -71,7 +72,6 @@ ShellClient::ShellClient(ShellSurfaceInterface *surface)
, m_shellSurface(surface)
, m_xdgShellSurface(nullptr)
, m_xdgShellPopup(nullptr)
, m_internal(surface->client() == waylandServer()->internalConnection())
{
setSurface(surface->surface());
init();
@ -83,7 +83,6 @@ ShellClient::ShellClient(XdgShellSurfaceInterface *surface)
, m_shellSurface(nullptr)
, m_xdgShellSurface(surface)
, m_xdgShellPopup(nullptr)
, m_internal(surface->client() == waylandServer()->internalConnection())
{
setSurface(surface->surface());
m_requestGeometryBlockCounter++;
@ -96,7 +95,6 @@ ShellClient::ShellClient(XdgShellPopupInterface *surface)
, m_shellSurface(nullptr)
, m_xdgShellSurface(nullptr)
, m_xdgShellPopup(surface)
, m_internal(surface->client() == waylandServer()->internalConnection())
{
setSurface(surface->surface());
m_requestGeometryBlockCounter++;
@ -228,9 +226,7 @@ void ShellClient::init()
} else {
ready_for_painting = false;
}
if (!m_internal) {
doSetGeometry(QRect(QPoint(0, 0), m_clientSize));
}
if (waylandServer()->inputMethodConnection() == s->client()) {
m_windowType = NET::OnScreenDisplay;
}
@ -337,7 +333,7 @@ void ShellClient::init()
}
// set initial desktop
setDesktop(m_internal ? int(NET::OnAllDesktops) : VirtualDesktopManager::self()->current());
setDesktop(VirtualDesktopManager::self()->current());
// setup shadow integration
getShadow();
@ -1159,9 +1155,7 @@ bool ShellClient::acceptsFocus() const
void ShellClient::createWindowId()
{
if (!m_internal) {
m_windowId = waylandServer()->createWindowId(surface());
}
}
pid_t ShellClient::pid() const
@ -1179,11 +1173,11 @@ bool ShellClient::isInputMethod() const
return surface()->client() == waylandServer()->inputMethodConnection();
}
bool ShellClient::requestGeometry(const QRect &rect)
void ShellClient::requestGeometry(const QRect &rect)
{
if (m_requestGeometryBlockCounter != 0) {
m_blockedRequestGeometry = rect;
return false;
return;
}
QSize size;
@ -1220,7 +1214,6 @@ bool ShellClient::requestGeometry(const QRect &rect)
}
m_blockedRequestGeometry = QRect();
return true;
}
void ShellClient::updatePendingGeometry()
@ -1292,12 +1285,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).
// This is a workaround.
if (!m_internal || rect.isValid()) {
doSetGeometry(rect);
}
};
auto updateRole = [this, surface] {
NET::WindowType type = NET::Unknown;
@ -1824,9 +1812,6 @@ void ShellClient::installXdgDecoration(XdgDecorationInterface *deco)
bool ShellClient::shouldExposeToWindowManagement()
{
if (m_internal) {
return false;
}
if (isLockScreen()) {
return false;
}
@ -1869,21 +1854,6 @@ void ShellClient::doMinimize()
workspace()->updateMinimizedOfTransients(this);
}
bool ShellClient::setupCompositing()
{
if (m_compositingSetup) {
return true;
}
m_compositingSetup = Toplevel::setupCompositing();
return m_compositingSetup;
}
void ShellClient::finishCompositing(ReleaseReason releaseReason)
{
m_compositingSetup = false;
Toplevel::finishCompositing(releaseReason);
}
void ShellClient::placeIn(const QRect &area)
{
Placement::self()->place(this, area);
@ -1997,11 +1967,6 @@ bool ShellClient::isPopupWindow() const
return false;
}
QWindow *ShellClient::internalWindow() const
{
return nullptr;
}
bool ShellClient::supportsWindowRules() const
{
if (m_plasmaShellSurface) {

View file

@ -4,6 +4,7 @@
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright (C) 2018 David Edmundson <davidedmundson@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -125,7 +126,6 @@ public:
bool isLockScreen() const override;
bool isInputMethod() const override;
virtual QWindow *internalWindow() const;
void installPlasmaShellSurface(KWayland::Server::PlasmaShellSurfaceInterface *surface);
void installServerSideDecoration(KWayland::Server::ServerSideDecorationInterface *decoration);
@ -140,10 +140,6 @@ public:
QRect transientPlacement(const QRect &bounds) const override;
QMatrix4x4 inputTransformation() const override;
bool setupCompositing() override;
void finishCompositing(ReleaseReason releaseReason = ReleaseReason::Release) override;
void showOnScreenEdge() override;
void killWindow() override;
@ -180,19 +176,6 @@ protected:
void doMinimize() 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);
@ -222,6 +205,10 @@ private:
// called on surface commit and processes all m_pendingConfigureRequests up to m_lastAckedConfigureReqest
void updatePendingGeometry();
QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize) const;
void requestGeometry(const QRect &rect);
void doSetGeometry(const QRect &rect);
void unmap();
void markAsMapped();
static void deleteClient(ShellClient *c);
QSize toWindowGeometry(const QSize &geometry) const;
@ -267,7 +254,6 @@ private:
bool m_fullScreen = false;
bool m_transient = false;
bool m_hidden = false;
bool m_internal;
bool m_hasPopupGrab = false;
qreal m_opacity = 1.0;
@ -297,7 +283,6 @@ private:
QMargins m_windowMargins;
bool m_compositingSetup = false;
bool m_isInitialized = false;
friend class Workspace;

View file

@ -355,7 +355,7 @@ void TabBoxHandlerImpl::highlightWindows(TabBoxClient *window, QWindow *controll
if (window) {
windows << static_cast<TabBoxClientImpl*>(window)->client()->effectWindow();
}
if (auto t = Workspace::self()->findToplevel(controller)) {
if (Toplevel *t = workspace()->findInternal(controller)) {
windows << t->effectWindow();
}
static_cast<EffectsHandlerImpl*>(effects)->highlightWindows(windows);

View file

@ -558,6 +558,11 @@ qreal Toplevel::screenScale() const
return m_screenScale;
}
qreal Toplevel::bufferScale() const
{
return surface() ? surface()->scale() : 1;
}
bool Toplevel::isOnScreen(int screen) const
{
return screens()->geometry(screen).intersects(geometry());
@ -770,15 +775,6 @@ QRegion Toplevel::inputShape() const
}
}
void Toplevel::setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo)
{
if (m_internalFBO != fbo) {
discardWindowPixmap();
m_internalFBO = fbo;
}
setDepth(32);
}
QMatrix4x4 Toplevel::inputTransformation() const
{
QMatrix4x4 m;

View file

@ -285,6 +285,13 @@ public:
* @since 5.12
*/
qreal screenScale() const; //
/**
* Returns the ratio between physical pixels and device-independent pixels for
* the attached buffer (or pixmap).
*
* For X11 clients, this method always returns 1.
*/
virtual qreal bufferScale() const;
virtual QPoint clientPos() const = 0; // inside of geometry()
/**
* Describes how the client's content maps to the window geometry including the frame.
@ -441,8 +448,8 @@ public:
KWayland::Server::SurfaceInterface *surface() const;
void setSurface(KWayland::Server::SurfaceInterface *surface);
virtual void setInternalFramebufferObject(const QSharedPointer<QOpenGLFramebufferObject> &fbo);
const QSharedPointer<QOpenGLFramebufferObject> &internalFramebufferObject() const;
QImage internalImageObject() const;
/**
* @returns Transformation to map from global to window coordinates.
@ -626,6 +633,11 @@ protected:
bool ready_for_painting;
QRegion repaints_region; // updating, repaint just requires repaint of that area
QRegion layer_repaints_region;
/**
* An FBO object KWin internal windows might render to.
*/
QSharedPointer<QOpenGLFramebufferObject> m_internalFBO;
QImage m_internalImage;
protected:
bool m_isDamaged;
@ -649,10 +661,6 @@ private:
bool m_skipCloseAnimation;
quint32 m_surfaceId = 0;
KWayland::Server::SurfaceInterface *m_surface = nullptr;
/**
* An FBO object KWin internal windows might render to.
*/
QSharedPointer<QOpenGLFramebufferObject> m_internalFBO;
// when adding new data members, check also copyToDeleted()
qreal m_screenScale = 1.0;
};
@ -919,6 +927,11 @@ inline const QSharedPointer<QOpenGLFramebufferObject> &Toplevel::internalFramebu
return m_internalFBO;
}
inline QImage Toplevel::internalImageObject() const
{
return m_internalImage;
}
inline QPoint Toplevel::clientContentPos() const
{
return QPoint(0, 0);

View file

@ -22,7 +22,6 @@ 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"
@ -159,12 +158,7 @@ void WaylandServer::createSurface(T *surface)
if (surface->client() == m_screenLockerClientConnection) {
ScreenLocker::KSldApp::self()->lockScreenShown();
}
ShellClient *client;
if (surface->client() == waylandServer()->internalConnection()) {
client = new InternalClient(surface);
} else {
client = new ShellClient(surface);
}
ShellClient *client = new ShellClient(surface);
if (ServerSideDecorationInterface *deco = ServerSideDecorationInterface::get(surface->surface())) {
client->installServerSideDecoration(deco);
}
@ -183,11 +177,7 @@ void WaylandServer::createSurface(T *surface)
if (auto palette = m_paletteManager->paletteForSurface(surface->surface())) {
client->installPalette(palette);
}
if (client->isInternal()) {
m_internalClients << client;
} else {
m_clients << client;
}
if (client->readyForPainting()) {
emit shellClientAdded(client);
} else {
@ -650,7 +640,6 @@ void WaylandServer::createInternalConnection()
void WaylandServer::removeClient(ShellClient *c)
{
m_clients.removeAll(c);
m_internalClients.removeAll(c);
emit shellClientRemoved(c);
}
@ -699,9 +688,6 @@ ShellClient *WaylandServer::findClient(quint32 id) const
if (ShellClient *c = findClientInList(m_clients, id)) {
return c;
}
if (ShellClient *c = findClientInList(m_internalClients, id)) {
return c;
}
return nullptr;
}
@ -713,9 +699,6 @@ ShellClient *WaylandServer::findClient(SurfaceInterface *surface) const
if (ShellClient *c = findClientInList(m_clients, surface)) {
return c;
}
if (ShellClient *c = findClientInList(m_internalClients, surface)) {
return c;
}
return nullptr;
}
@ -724,22 +707,6 @@ AbstractClient *WaylandServer::findAbstractClient(SurfaceInterface *surface) con
return findClient(surface);
}
ShellClient *WaylandServer::findClient(QWindow *w) const
{
if (!w) {
return nullptr;
}
auto it = std::find_if(m_internalClients.constBegin(), m_internalClients.constEnd(),
[w] (const ShellClient *c) {
return c->internalWindow() == w;
}
);
if (it != m_internalClients.constEnd()) {
return *it;
}
return nullptr;
}
quint32 WaylandServer::createWindowId(SurfaceInterface *surface)
{
auto it = m_clientIds.constFind(surface->client());

View file

@ -126,14 +126,10 @@ public:
QList<ShellClient*> clients() const {
return m_clients;
}
QList<ShellClient*> internalClients() const {
return m_internalClients;
}
void removeClient(ShellClient *c);
ShellClient *findClient(quint32 id) const;
ShellClient *findClient(KWayland::Server::SurfaceInterface *surface) const;
AbstractClient *findAbstractClient(KWayland::Server::SurfaceInterface *surface) const;
ShellClient *findClient(QWindow *w) const;
/**
* @returns a transient parent of a surface imported with the foreign protocol, if any
@ -277,7 +273,6 @@ private:
KWayland::Server::XdgForeignInterface *m_XdgForeign = nullptr;
KWayland::Server::KeyStateInterface *m_keyState = nullptr;
QList<ShellClient*> m_clients;
QList<ShellClient*> m_internalClients;
QHash<KWayland::Server::ClientConnection*, quint16> m_clientIds;
InitalizationFlags m_initFlags;
QVector<KWayland::Server::PlasmaShellSurfaceInterface*> m_plasmaShellSurfaces;

View file

@ -4,6 +4,7 @@
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -37,6 +38,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "focuschain.h"
#include "group.h"
#include "input.h"
#include "internal_client.h"
#include "logind.h"
#include "moving_client_x11_filter.h"
#include "killwindow.h"
@ -562,16 +564,15 @@ Workspace::~Workspace()
for (ShellClient *shellClient : shellClients) {
shellClient->destroyClient();
}
const QList<ShellClient *> internalClients = waylandServer()->internalClients();
for (ShellClient *internalClient : internalClients) {
internalClient->destroyClient();
}
}
for (UnmanagedList::iterator it = unmanaged.begin(), end = unmanaged.end(); it != end; ++it)
(*it)->release(ReleaseReason::KWinShutsDown);
for (InternalClient *client : m_internalClients) {
client->destroyClient();
}
if (auto c = kwinApp()->x11Connection()) {
xcb_delete_property(c, kwinApp()->x11RootWindow(), atoms->kwin_running);
}
@ -1667,11 +1668,9 @@ AbstractClient *Workspace::findAbstractClient(std::function<bool (const Abstract
if (Client *ret = Toplevel::findInList(desktops, func)) {
return ret;
}
if (waylandServer()) {
if (AbstractClient *ret = Toplevel::findInList(waylandServer()->internalClients(), func)) {
if (InternalClient *ret = Toplevel::findInList(m_internalClients, func)) {
return ret;
}
}
return nullptr;
}
@ -1721,22 +1720,12 @@ Toplevel *Workspace::findToplevel(std::function<bool (const Toplevel*)> func) co
if (Unmanaged *ret = Toplevel::findInList(unmanaged, func)) {
return ret;
}
if (InternalClient *ret = Toplevel::findInList(m_internalClients, func)) {
return ret;
}
return nullptr;
}
Toplevel *Workspace::findToplevel(QWindow *w) const
{
if (!w) {
return nullptr;
}
if (waylandServer()) {
if (auto c = waylandServer()->findClient(w)) {
return c;
}
}
return findUnmanaged(w->winId());
}
bool Workspace::hasClient(const AbstractClient *c)
{
if (auto cc = dynamic_cast<const Client*>(c)) {
@ -1753,6 +1742,7 @@ void Workspace::forEachAbstractClient(std::function< void (AbstractClient*) > fu
{
std::for_each(m_allClients.constBegin(), m_allClients.constEnd(), func);
std::for_each(desktops.constBegin(), desktops.constEnd(), func);
std::for_each(m_internalClients.constBegin(), m_internalClients.constEnd(), func);
}
Toplevel *Workspace::findInternal(QWindow *w) const
@ -1762,9 +1752,13 @@ Toplevel *Workspace::findInternal(QWindow *w) const
}
if (kwinApp()->operationMode() == Application::OperationModeX11) {
return findUnmanaged(w->winId());
} else {
return waylandServer()->findClient(w);
}
for (InternalClient *client : m_internalClients) {
if (client->internalWindow() == w) {
return client;
}
}
return nullptr;
}
bool Workspace::compositing() const
@ -1804,5 +1798,33 @@ void Workspace::updateTabbox()
#endif
}
} // namespace
void Workspace::addInternalClient(InternalClient *client)
{
m_internalClients.append(client);
setupClientConnections(client);
client->updateLayer();
if (client->isDecorated()) {
client->keepInArea(clientArea(FullScreenArea, client));
}
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
emit internalClientAdded(client);
}
void Workspace::removeInternalClient(InternalClient *client)
{
m_internalClients.removeOne(client);
markXStackingOrderAsDirty();
updateStackingOrder(true);
updateClientArea();
emit internalClientRemoved(client);
}
} // namespace

View file

@ -5,6 +5,7 @@
Copyright (C) 1999, 2000 Matthias Ettrich <ettrich@kde.org>
Copyright (C) 2003 Lubos Lunak <l.lunak@kde.org>
Copyright (C) 2009 Lucas Murray <lmurray@undefinedfire.com>
Copyright (C) 2019 Vlad Zagorodniy <vladzzag@gmail.com>
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
@ -53,6 +54,7 @@ class Window;
class AbstractClient;
class Client;
class Compositor;
class InternalClient;
class KillWindow;
class ShortcutDialog;
class UserActionsMenu;
@ -127,11 +129,6 @@ public:
Unmanaged *findUnmanaged(xcb_window_t w) const;
void forEachUnmanaged(std::function<void (Unmanaged*)> func);
Toplevel *findToplevel(std::function<bool (const Toplevel*)> func) const;
/**
* Finds the Toplevel for the KWin internal window @p w.
* On Wayland this is normally a ShellClient. For X11 an Unmanaged.
*/
Toplevel *findToplevel(QWindow *w) const;
/**
* @brief Finds a Toplevel for the internal window @p w.
*
@ -238,6 +235,13 @@ public:
return m_allClients;
}
/**
* @returns List of all internal clients currently managed by Workspace
*/
const QList<InternalClient *> &internalClients() const {
return m_internalClients;
}
void stackScreenEdgesUnderOverrideRedirect();
public:
@ -392,6 +396,26 @@ public:
return client_keys_dialog;
}
/**
* Adds the internal client to Workspace.
*
* This method will be called by InternalClient when it's mapped.
*
* @see internalClientAdded
* @internal
*/
void addInternalClient(InternalClient *client);
/**
* Removes the internal client from Workspace.
*
* This method is meant to be called only by InternalClient.
*
* @see internalClientRemoved
* @internal
*/
void removeInternalClient(InternalClient *client);
public Q_SLOTS:
void performWindowOperation(KWin::AbstractClient* c, Options::WindowOperation op);
// Keybindings
@ -497,6 +521,16 @@ Q_SIGNALS:
*/
void stackingOrderChanged();
/**
* This signal is emitted whenever an internal client is created.
*/
void internalClientAdded(KWin::InternalClient *client);
/**
* This signal is emitted whenever an internal client gets removed.
*/
void internalClientRemoved(KWin::InternalClient *client);
private:
void init();
void initWithX11();
@ -564,6 +598,7 @@ private:
ClientList desktops;
UnmanagedList unmanaged;
DeletedList deleted;
QList<InternalClient *> m_internalClients;
ToplevelList unconstrained_stacking_order; // Topmost last
ToplevelList stacking_order; // Topmost last