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:
parent
ca1f66b1df
commit
bebe81209c
45 changed files with 1128 additions and 893 deletions
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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::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());
|
||||
|
|
|
@ -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::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));
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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::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*>();
|
||||
|
|
|
@ -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::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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
23
effects.cpp
23
effects.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
11
input.cpp
11
input.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
}
|
||||
setOpacity(m_internalWindow->opacity());
|
||||
|
||||
// skip close animation support
|
||||
setCaption(m_internalWindow->title());
|
||||
setIcon(QIcon::fromTheme(QStringLiteral("kwin")));
|
||||
setOnAllDesktops(true);
|
||||
setOpacity(m_internalWindow->opacity());
|
||||
setSkipCloseAnimation(m_internalWindow->property(s_skipClosePropertyName).toBool());
|
||||
|
||||
setupCompositing();
|
||||
updateColorScheme();
|
||||
|
||||
blockGeometryUpdates(true);
|
||||
commitGeometry(m_internalWindow->geometry());
|
||||
updateDecoration(true);
|
||||
setGeometry(mapFromClient(m_internalWindow->geometry()));
|
||||
setGeometryRestore(geometry());
|
||||
blockGeometryUpdates(false);
|
||||
|
||||
m_internalWindow->installEventFilter(this);
|
||||
return;
|
||||
}
|
||||
|
||||
qCWarning(KWIN_CORE, "Couldn't find an internal window for surface with id %x", surface()->id());
|
||||
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();
|
||||
}
|
||||
|
||||
QWindow *InternalClient::internalWindow() const
|
||||
if (geom == rect) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QRect newClientGeometry = mapToClient(rect);
|
||||
|
||||
if (m_clientSize == newClientGeometry.size()) {
|
||||
commitGeometry(rect);
|
||||
} else {
|
||||
requestGeometry(rect);
|
||||
}
|
||||
}
|
||||
|
||||
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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
}
|
||||
|
|
12
layers.cpp
12
layers.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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 ®ion)
|
||||
{
|
||||
for (const QRect &rect : region) {
|
||||
blitImage(source, target, rect);
|
||||
}
|
||||
}
|
||||
|
||||
void BackingStore::flush(QWindow *window, const QRegion ®ion, 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 ®ion, 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
return m_shellClient;
|
||||
if (m_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
int Window::scale() const
|
||||
{
|
||||
return m_scale;
|
||||
m_handle = new InternalClient(window());
|
||||
}
|
||||
|
||||
qreal Window::devicePixelRatio() const
|
||||
void Window::unmap()
|
||||
{
|
||||
return m_scale;
|
||||
if (!m_handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_handle->destroyClient();
|
||||
m_handle = nullptr;
|
||||
|
||||
m_contentFBO = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
18
scene.cpp
18
scene.cpp
|
@ -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);
|
||||
|
|
8
scene.h
8
scene.h
|
@ -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()
|
||||
|
|
|
@ -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,10 +1155,8 @@ 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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
14
toplevel.cpp
14
toplevel.cpp
|
@ -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;
|
||||
|
|
23
toplevel.h
23
toplevel.h
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
45
workspace.h
45
workspace.h
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue