scripting: ClientModel -> WindowModel

This commit is contained in:
Vlad Zahorodnii 2023-02-09 19:47:44 +02:00
parent 88cf83554f
commit 37bcdbc03e
14 changed files with 461 additions and 461 deletions

View file

@ -137,7 +137,6 @@ target_sources(kwin PRIVATE
scene/workspacescene_opengl.cpp
scene/workspacescene_qpainter.cpp
screenedge.cpp
scripting/clientmodel.cpp
scripting/dbuscall.cpp
scripting/desktopbackgrounditem.cpp
scripting/screenedgeitem.cpp
@ -147,6 +146,7 @@ target_sources(kwin PRIVATE
scripting/scriptingutils.cpp
scripting/tilemodel.cpp
scripting/virtualdesktopmodel.cpp
scripting/windowmodel.cpp
scripting/windowthumbnailitem.cpp
scripting/workspace_wrapper.cpp
shadow.cpp

View file

@ -16,7 +16,7 @@ import org.kde.kwin.private.desktopgrid 1.0
FocusScope {
id: desktopView
required property QtObject clientModel
required property QtObject windowModel
required property QtObject desktop
required property var dndManagerStore
readonly property bool dragActive: heap.dragActive || dragHandler.active || xAnim.running || yAnim.running
@ -65,22 +65,22 @@ FocusScope {
}
}
Repeater {
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
activity: KWinComponents.Workspace.currentActivity
desktop: desktopView.desktop
screenName: targetScreen.name
clientModel: desktopView.clientModel
windowType: KWinComponents.ClientFilterModel.Dock | KWinComponents.ClientFilterModel.Desktop
windowModel: desktopView.windowModel
windowType: KWinComponents.WindowFilterModel.Dock | KWinComponents.WindowFilterModel.Desktop
}
KWinComponents.WindowThumbnailItem {
wId: model.client.internalId
x: model.client.x - targetScreen.geometry.x
y: model.client.y - targetScreen.geometry.y
z: model.client.stackingOrder
width: model.client.width
height: model.client.height
opacity: model.client.dock ? desktopView.panelOpacity : 1
wId: model.window.internalId
x: model.window.x - targetScreen.geometry.x
y: model.window.y - targetScreen.geometry.y
z: model.window.stackingOrder
width: model.window.width
height: model.window.height
opacity: model.window.dock ? desktopView.panelOpacity : 1
}
}
@ -117,15 +117,15 @@ FocusScope {
organized: container.organized
layout.mode: effect.layout
dndManagerStore: desktopView.dndManagerStore
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
activity: KWinComponents.Workspace.currentActivity
desktop: desktopView.desktop
screenName: targetScreen.name
clientModel: desktopView.clientModel
windowType: ~KWinComponents.ClientFilterModel.Dock &
~KWinComponents.ClientFilterModel.Desktop &
~KWinComponents.ClientFilterModel.Notification &
~KWinComponents.ClientFilterModel.CriticalNotification
windowModel: desktopView.windowModel
windowType: ~KWinComponents.WindowFilterModel.Dock &
~KWinComponents.WindowFilterModel.Desktop &
~KWinComponents.WindowFilterModel.Notification &
~KWinComponents.WindowFilterModel.CriticalNotification
}
delegate: WindowHeapDelegate {
windowHeap: heap

View file

@ -153,7 +153,7 @@ Rectangle {
KWinComponents.VirtualDesktopModel {
id: desktopModel
}
KWinComponents.ClientModel {
KWinComponents.WindowModel {
id: stackModel
}
@ -268,7 +268,7 @@ Rectangle {
width: container.width
height: container.height
clientModel: stackModel
windowModel: stackModel
dndManagerStore: container.dndManagerStore
Rectangle {
anchors.fill: parent

View file

@ -22,7 +22,7 @@ Item {
readonly property real desktopWidth: desktopHeight * targetScreen.geometry.width / targetScreen.geometry.height
readonly property real columnHeight: desktopHeight + PlasmaCore.Units.gridUnit
property QtObject clientModel
property QtObject windowModel
property alias desktopModel: desktopRepeater.model
property QtObject selectedDesktop: null
property WindowHeap heap
@ -100,7 +100,7 @@ Item {
width: targetScreen.geometry.width
height: targetScreen.geometry.height
visible: scaled
clientModel: bar.clientModel
windowModel: bar.windowModel
desktop: delegate.desktop
scale: bar.desktopHeight / targetScreen.geometry.height
transformOrigin: Item.TopLeft

View file

@ -10,25 +10,25 @@ import org.kde.kwin 3.0 as KWinComponents
Item {
id: desktopView
required property QtObject clientModel
required property QtObject windowModel
required property QtObject desktop
Repeater {
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
activity: KWinComponents.Workspace.currentActivity
desktop: desktopView.desktop
screenName: targetScreen.name
clientModel: desktopView.clientModel
windowModel: desktopView.windowModel
}
KWinComponents.WindowThumbnailItem {
wId: model.client.internalId
x: model.client.x - targetScreen.geometry.x
y: model.client.y - targetScreen.geometry.y
width: model.client.width
height: model.client.height
z: model.client.stackingOrder
visible: !model.client.minimized
wId: model.window.internalId
x: model.window.x - targetScreen.geometry.x
y: model.window.y - targetScreen.geometry.y
width: model.window.width
height: model.window.height
z: model.window.stackingOrder
visible: !model.window.minimized
}
}
}

View file

@ -183,7 +183,7 @@ FocusScope {
DesktopBar {
id: bar
anchors.fill: parent
clientModel: stackModel
windowModel: stackModel
desktopModel: desktopModel
selectedDesktop: KWinComponents.Workspace.currentDesktop
heap: heap
@ -238,17 +238,17 @@ FocusScope {
organized: container.organized
Keys.priority: Keys.AfterItem
Keys.forwardTo: searchResults
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
activity: KWinComponents.Workspace.currentActivity
desktop: KWinComponents.Workspace.currentDesktop
screenName: targetScreen.name
clientModel: stackModel
windowModel: stackModel
filter: effect.searchText
minimizedWindows: !effect.ignoreMinimized
windowType: ~KWinComponents.ClientFilterModel.Dock &
~KWinComponents.ClientFilterModel.Desktop &
~KWinComponents.ClientFilterModel.Notification &
~KWinComponents.ClientFilterModel.CriticalNotification
windowType: ~KWinComponents.WindowFilterModel.Dock &
~KWinComponents.WindowFilterModel.Desktop &
~KWinComponents.WindowFilterModel.Notification &
~KWinComponents.WindowFilterModel.CriticalNotification
}
delegate: WindowHeapDelegate {
windowHeap: heap
@ -267,7 +267,7 @@ FocusScope {
}
opacity: 1 - downGestureProgress
onDownGestureTriggered: client.closeWindow()
onDownGestureTriggered: window.closeWindow()
}
onActivated: effect.deactivate();
onWindowClicked: {
@ -294,25 +294,25 @@ FocusScope {
}
Repeater {
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
desktop: KWinComponents.Workspace.currentDesktop
screenName: targetScreen.name
clientModel: stackModel
windowType: KWinComponents.ClientFilterModel.Dock
windowModel: stackModel
windowType: KWinComponents.WindowFilterModel.Dock
}
KWinComponents.WindowThumbnailItem {
id: windowThumbnail
visible: !model.client.hidden && opacity > 0
wId: model.client.internalId
x: model.client.x - targetScreen.geometry.x
y: model.client.y - targetScreen.geometry.y
z: model.client.stackingOrder
width: model.client.width
height: model.client.height
visible: !model.window.hidden && opacity > 0
wId: model.window.internalId
x: model.window.x - targetScreen.geometry.x
y: model.window.y - targetScreen.geometry.y
z: model.window.stackingOrder
width: model.window.width
height: model.window.height
opacity: container.effect.gestureInProgress
? 1 - container.effect.partialActivationFactor
: (model.client.hidden || container.organized) ? 0 : 1
: (model.window.hidden || container.organized) ? 0 : 1
Behavior on opacity {
enabled: !container.effect.gestureInProgress
@ -321,7 +321,7 @@ FocusScope {
}
}
KWinComponents.ClientModel {
KWinComponents.WindowModel {
id: stackModel
}

View file

@ -43,7 +43,7 @@ FocusScope {
property bool animationEnabled: false
property bool absolutePositioning: true
property real padding: 0
// Either a string "activeClass" or a list internalIds of clients
// Either a string "activeClass" or a list internalIds of windows
property var showOnly: []
required property bool organized
@ -55,7 +55,7 @@ FocusScope {
signal windowClicked(QtObject window, EventPoint eventPoint)
function activateIndex(index) {
KWinComponents.Workspace.activeClient = windowsInstantiator.objectAt(index).client;
KWinComponents.Workspace.activeClient = windowsInstantiator.objectAt(index).window;
activated();
}
@ -142,7 +142,7 @@ FocusScope {
onObjectAdded: (index, object) => {
object.parent = expoLayout
var key = object.client.internalId;
var key = object.window.internalId;
if (heap.containsDND(key)) {
expoLayout.forceLayout();
var oldGlobalRect = heap.restoreDND(key);
@ -372,7 +372,7 @@ FocusScope {
}
if (selectedItem) {
handled = true;
KWinComponents.Workspace.activeClient = selectedItem.client;
KWinComponents.Workspace.activeClient = selectedItem.window;
activated();
}
break;

View file

@ -16,25 +16,25 @@ import org.kde.plasma.core 2.0 as PlasmaCore
Item {
id: thumb
required property QtObject client
required property QtObject window
required property int index
required property Item windowHeap
readonly property bool selected: windowHeap.selectedIndex === index
// no desktops is a special value which means "All Desktops"
readonly property bool presentOnCurrentDesktop: !client.desktops.length || client.desktops.indexOf(KWinComponents.Workspace.currentDesktop) !== -1
readonly property bool initialHidden: client.minimized || !presentOnCurrentDesktop
readonly property bool presentOnCurrentDesktop: !window.desktops.length || window.desktops.indexOf(KWinComponents.Workspace.currentDesktop) !== -1
readonly property bool initialHidden: window.minimized || !presentOnCurrentDesktop
readonly property bool activeHidden: {
if (windowHeap.showOnly === "activeClass") {
if (!KWinComponents.Workspace.activeClient) {
return true;
} else {
return KWinComponents.Workspace.activeClient.resourceName !== client.resourceName;
return KWinComponents.Workspace.activeClient.resourceName !== window.resourceName;
}
} else {
return windowHeap.showOnly.length !== 0
&& windowHeap.showOnly.indexOf(client.internalId) === -1;
&& windowHeap.showOnly.indexOf(window.internalId) === -1;
}
}
@ -70,7 +70,7 @@ Item {
visible: opacity > 0
z: (activeDragHandler.active || returning.running) ? 1000
: client.stackingOrder * (presentOnCurrentDesktop ? 1 : 0.001)
: window.stackingOrder * (presentOnCurrentDesktop ? 1 : 0.001)
function restoreDND(oldGlobalRect: rect) {
thumbSource.restoreDND(oldGlobalRect);
@ -91,11 +91,11 @@ Item {
KWinComponents.WindowThumbnailItem {
id: thumbSource
wId: thumb.client.internalId
wId: thumb.window.internalId
Drag.proposedAction: Qt.MoveAction
Drag.supportedActions: Qt.MoveAction
Drag.source: thumb.client
Drag.source: thumb.window
Drag.hotSpot: Qt.point(
thumb.activeDragHandler.centroid.pressPosition.x * thumb.targetScale,
thumb.activeDragHandler.centroid.pressPosition.y * thumb.targetScale)
@ -105,7 +105,7 @@ Item {
function saveDND() {
const oldGlobalRect = mapToItem(null, 0, 0, width, height);
thumb.windowHeap.saveDND(thumb.client.internalId, oldGlobalRect);
thumb.windowHeap.saveDND(thumb.window.internalId, oldGlobalRect);
}
function restoreDND(oldGlobalRect: rect) {
thumb.substate = "reparenting";
@ -120,7 +120,7 @@ Item {
thumb.substate = "normal";
}
function deleteDND() {
thumb.windowHeap.deleteDND(thumb.client.internalId);
thumb.windowHeap.deleteDND(thumb.window.internalId);
}
PlasmaCore.FrameSvgItem {
@ -157,7 +157,7 @@ Item {
id: icon
width: PlasmaCore.Units.iconSizes.large
height: PlasmaCore.Units.iconSizes.large
source: thumb.client.icon
source: thumb.window.icon
usesPlasmaTheme: false
anchors.horizontalCenter: thumbSource.horizontalCenter
anchors.bottom: thumbSource.bottom
@ -171,7 +171,7 @@ Item {
anchors.top: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
elide: Text.ElideRight
text: thumb.client.caption
text: thumb.window.caption
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
@ -181,11 +181,11 @@ Item {
id: cell
layout: windowHeap.layout
enabled: !thumb.activeHidden
naturalX: thumb.client.x
naturalY: thumb.client.y
naturalWidth: thumb.client.width
naturalHeight: thumb.client.height
persistentKey: thumb.client.internalId
naturalX: thumb.window.x
naturalY: thumb.window.y
naturalWidth: thumb.window.width
naturalHeight: thumb.window.height
persistentKey: thumb.window.internalId
bottomMargin: icon.height / 4 + (thumb.windowTitleVisible ? caption.height : 0)
}
@ -194,17 +194,17 @@ Item {
name: "initial"
PropertyChanges {
target: thumb
x: thumb.client.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.x : 0)
y: thumb.client.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.y : 0)
width: thumb.client.width
height: thumb.client.height
x: thumb.window.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.x : 0)
y: thumb.window.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.y : 0)
width: thumb.window.width
height: thumb.window.height
}
PropertyChanges {
target: thumbSource
x: 0
y: 0
width: thumb.client.width
height: thumb.client.height
width: thumb.window.width
height: thumb.window.height
}
PropertyChanges {
target: icon
@ -219,10 +219,10 @@ Item {
name: "partial"
PropertyChanges {
target: thumb
x: (thumb.client.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.x : 0)) * (1 - effect.partialActivationFactor) + cell.x * effect.partialActivationFactor
y: (thumb.client.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.y : 0)) * (1 - effect.partialActivationFactor) + cell.y * effect.partialActivationFactor
width: thumb.client.width * (1 - effect.partialActivationFactor) + cell.width * effect.partialActivationFactor
height: thumb.client.height * (1 - effect.partialActivationFactor) + cell.height * effect.partialActivationFactor
x: (thumb.window.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.x : 0)) * (1 - effect.partialActivationFactor) + cell.x * effect.partialActivationFactor
y: (thumb.window.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.y : 0)) * (1 - effect.partialActivationFactor) + cell.y * effect.partialActivationFactor
width: thumb.window.width * (1 - effect.partialActivationFactor) + cell.width * effect.partialActivationFactor
height: thumb.window.height * (1 - effect.partialActivationFactor) + cell.height * effect.partialActivationFactor
opacity: thumb.initialHidden
? (thumb.activeHidden ? 0 : effect.partialActivationFactor)
: (thumb.activeHidden ? 1 - effect.partialActivationFactor : 1)
@ -354,7 +354,7 @@ Item {
TapHandler {
acceptedButtons: Qt.LeftButton
onTapped: {
KWinComponents.Workspace.activeClient = thumb.client;
KWinComponents.Workspace.activeClient = thumb.window;
thumb.windowHeap.activated();
}
onPressedChanged: {
@ -375,7 +375,7 @@ Item {
acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
onTapped: {
thumb.windowHeap.windowClicked(thumb.client, eventPoint)
thumb.windowHeap.windowClicked(thumb.window, eventPoint)
}
}
@ -455,7 +455,7 @@ Item {
margins: PlasmaCore.Units.smallSpacing
}
visible: thumb.closeButtonVisible && (hoverHandler.hovered || Kirigami.Settings.tabletMode || Kirigami.Settings.hasTransientTouchInput) && thumb.client.closeable && !thumb.activeDragHandler.active
visible: thumb.closeButtonVisible && (hoverHandler.hovered || Kirigami.Settings.tabletMode || Kirigami.Settings.hasTransientTouchInput) && thumb.window.closeable && !thumb.activeDragHandler.active
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
text: i18ndc("kwin_effects", "@info:tooltip as in: 'close this window'", "Close window")
@ -467,7 +467,7 @@ Item {
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay
Accessible.name: text
onClicked: thumb.client.closeWindow();
onClicked: thumb.window.closeWindow();
}
Component.onDestruction: {

View file

@ -51,21 +51,21 @@ FocusScope {
anchors.fill: parent
Repeater {
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
activity: KWinComponents.Workspace.currentActivity
desktop: KWinComponents.Workspace.currentDesktop
screenName: targetScreen.name
clientModel: KWinComponents.ClientModel {}
windowModel: KWinComponents.WindowModel {}
}
KWinComponents.WindowThumbnailItem {
wId: model.client.internalId
x: model.client.x - targetScreen.geometry.x
y: model.client.y - targetScreen.geometry.y
width: model.client.width
height: model.client.height
z: model.client.stackingOrder
visible: !model.client.minimized
wId: model.window.internalId
x: model.window.x - targetScreen.geometry.x
y: model.window.y - targetScreen.geometry.y
width: model.window.width
height: model.window.height
z: model.window.stackingOrder
visible: !model.window.minimized
}
}
property real blurRadius: root.active ? 64 : 0

View file

@ -186,7 +186,7 @@ Item {
}
window.closeWindow();
}
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
activity: KWinComponents.Workspace.currentActivity
desktop: {
switch (container.effect.mode) {
@ -198,18 +198,18 @@ Item {
}
}
screenName: targetScreen.name
clientModel: stackModel
windowModel: stackModel
filter: effect.searchText
minimizedWindows: !effect.ignoreMinimized
windowType: ~KWinComponents.ClientFilterModel.Dock &
~KWinComponents.ClientFilterModel.Desktop &
~KWinComponents.ClientFilterModel.Notification &
~KWinComponents.ClientFilterModel.CriticalNotification
windowType: ~KWinComponents.WindowFilterModel.Dock &
~KWinComponents.WindowFilterModel.Desktop &
~KWinComponents.WindowFilterModel.Notification &
~KWinComponents.WindowFilterModel.CriticalNotification
}
delegate: WindowHeapDelegate {
windowHeap: heap
opacity: 1 - downGestureProgress
onDownGestureTriggered: client.closeWindow()
onDownGestureTriggered: window.closeWindow()
}
onActivated: effect.deactivate(container.effect.animationDuration);
}
@ -218,21 +218,21 @@ Item {
Instantiator {
asynchronous: true
model: KWinComponents.ClientFilterModel {
model: KWinComponents.WindowFilterModel {
desktop: KWinComponents.Workspace.currentDesktop
screenName: targetScreen.name
clientModel: stackModel
windowType: KWinComponents.ClientFilterModel.Dock
windowModel: stackModel
windowType: KWinComponents.WindowFilterModel.Dock
}
KWinComponents.WindowThumbnailItem {
id: windowThumbnail
wId: model.client.internalId
x: model.client.x - targetScreen.geometry.x
y: model.client.y - targetScreen.geometry.y
z: model.client.stackingOrder
wId: model.window.internalId
x: model.window.x - targetScreen.geometry.x
y: model.window.y - targetScreen.geometry.y
z: model.window.stackingOrder
visible: opacity > 0
opacity: (model.client.hidden || container.organized) ? 0 : 1
opacity: (model.window.hidden || container.organized) ? 0 : 1
Behavior on opacity {
NumberAnimation { duration: container.effect.animationDuration; easing.type: Easing.OutCubic }
@ -244,7 +244,7 @@ Item {
}
}
KWinComponents.ClientModel {
KWinComponents.WindowModel {
id: stackModel
}

View file

@ -1,330 +0,0 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "clientmodel.h"
#include "core/output.h"
#include "core/outputbackend.h"
#include "virtualdesktops.h"
#include "window.h"
#include "workspace.h"
namespace KWin
{
ClientModel::ClientModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(workspace(), &Workspace::windowAdded, this, &ClientModel::handleClientAdded);
connect(workspace(), &Workspace::windowRemoved, this, &ClientModel::handleClientRemoved);
m_clients = workspace()->allClientList();
for (Window *client : std::as_const(m_clients)) {
setupClientConnections(client);
}
}
void ClientModel::markRoleChanged(Window *client, int role)
{
const QModelIndex row = index(m_clients.indexOf(client), 0);
Q_EMIT dataChanged(row, row, {role});
}
void ClientModel::setupClientConnections(Window *client)
{
connect(client, &Window::desktopChanged, this, [this, client]() {
markRoleChanged(client, DesktopRole);
});
connect(client, &Window::outputChanged, this, [this, client]() {
markRoleChanged(client, OutputRole);
});
connect(client, &Window::activitiesChanged, this, [this, client]() {
markRoleChanged(client, ActivityRole);
});
}
void ClientModel::handleClientAdded(Window *client)
{
beginInsertRows(QModelIndex(), m_clients.count(), m_clients.count());
m_clients.append(client);
endInsertRows();
setupClientConnections(client);
}
void ClientModel::handleClientRemoved(Window *client)
{
const int index = m_clients.indexOf(client);
Q_ASSERT(index != -1);
beginRemoveRows(QModelIndex(), index, index);
m_clients.removeAt(index);
endRemoveRows();
}
QHash<int, QByteArray> ClientModel::roleNames() const
{
return {
{Qt::DisplayRole, QByteArrayLiteral("display")},
{ClientRole, QByteArrayLiteral("client")},
{OutputRole, QByteArrayLiteral("output")},
{DesktopRole, QByteArrayLiteral("desktop")},
{ActivityRole, QByteArrayLiteral("activity")},
};
}
QVariant ClientModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_clients.count()) {
return QVariant();
}
Window *client = m_clients[index.row()];
switch (role) {
case Qt::DisplayRole:
case ClientRole:
return QVariant::fromValue(client);
case OutputRole:
return QVariant::fromValue(client->output());
case DesktopRole:
return client->desktop();
case ActivityRole:
return client->activities();
default:
return QVariant();
}
}
int ClientModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_clients.count();
}
ClientFilterModel::ClientFilterModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
ClientModel *ClientFilterModel::clientModel() const
{
return m_clientModel;
}
void ClientFilterModel::setClientModel(ClientModel *clientModel)
{
if (clientModel == m_clientModel) {
return;
}
m_clientModel = clientModel;
setSourceModel(m_clientModel);
Q_EMIT clientModelChanged();
}
QString ClientFilterModel::activity() const
{
return m_activity.value_or(QString());
}
void ClientFilterModel::setActivity(const QString &activity)
{
if (m_activity != activity) {
m_activity = activity;
Q_EMIT activityChanged();
invalidateFilter();
}
}
void ClientFilterModel::resetActivity()
{
if (m_activity.has_value()) {
m_activity.reset();
Q_EMIT activityChanged();
invalidateFilter();
}
}
VirtualDesktop *ClientFilterModel::desktop() const
{
return m_desktop;
}
void ClientFilterModel::setDesktop(VirtualDesktop *desktop)
{
if (m_desktop != desktop) {
m_desktop = desktop;
Q_EMIT desktopChanged();
invalidateFilter();
}
}
void ClientFilterModel::resetDesktop()
{
setDesktop(nullptr);
}
QString ClientFilterModel::filter() const
{
return m_filter;
}
void ClientFilterModel::setFilter(const QString &filter)
{
if (filter == m_filter) {
return;
}
m_filter = filter;
Q_EMIT filterChanged();
invalidateFilter();
}
QString ClientFilterModel::screenName() const
{
return m_output ? m_output->name() : QString();
}
void ClientFilterModel::setScreenName(const QString &screen)
{
Output *output = kwinApp()->outputBackend()->findOutput(screen);
if (m_output != output) {
m_output = output;
Q_EMIT screenNameChanged();
invalidateFilter();
}
}
void ClientFilterModel::resetScreenName()
{
if (m_output) {
m_output = nullptr;
Q_EMIT screenNameChanged();
invalidateFilter();
}
}
ClientFilterModel::WindowTypes ClientFilterModel::windowType() const
{
return m_windowType.value_or(WindowTypes());
}
void ClientFilterModel::setWindowType(WindowTypes windowType)
{
if (m_windowType != windowType) {
m_windowType = windowType;
Q_EMIT windowTypeChanged();
invalidateFilter();
}
}
void ClientFilterModel::resetWindowType()
{
if (m_windowType.has_value()) {
m_windowType.reset();
Q_EMIT windowTypeChanged();
invalidateFilter();
}
}
void ClientFilterModel::setMinimizedWindows(bool show)
{
if (m_showMinimizedWindows == show) {
return;
}
m_showMinimizedWindows = show;
invalidateFilter();
Q_EMIT minimizedWindowsChanged();
}
bool ClientFilterModel::minimizedWindows() const
{
return m_showMinimizedWindows;
}
bool ClientFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (!m_clientModel) {
return false;
}
const QModelIndex index = m_clientModel->index(sourceRow, 0, sourceParent);
if (!index.isValid()) {
return false;
}
const QVariant data = index.data();
if (!data.isValid()) {
// an invalid QVariant is valid data
return true;
}
Window *client = qvariant_cast<Window *>(data);
if (!client) {
return false;
}
if (m_activity.has_value()) {
if (!client->isOnActivity(*m_activity)) {
return false;
}
}
if (m_desktop) {
if (!client->isOnDesktop(m_desktop)) {
return false;
}
}
if (m_output) {
if (!client->isOnOutput(m_output)) {
return false;
}
}
if (m_windowType.has_value()) {
if (!(windowTypeMask(client) & *m_windowType)) {
return false;
}
}
if (!m_filter.isEmpty()) {
if (client->caption().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
if (client->windowRole().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
if (client->resourceName().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
if (client->resourceClass().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
return false;
}
if (!m_showMinimizedWindows) {
return !client->isMinimized();
}
return true;
}
ClientFilterModel::WindowTypes ClientFilterModel::windowTypeMask(Window *client) const
{
WindowTypes mask;
if (client->isNormalWindow()) {
mask |= WindowType::Normal;
} else if (client->isDialog()) {
mask |= WindowType::Dialog;
} else if (client->isDock()) {
mask |= WindowType::Dock;
} else if (client->isDesktop()) {
mask |= WindowType::Desktop;
} else if (client->isNotification()) {
mask |= WindowType::Notification;
} else if (client->isCriticalNotification()) {
mask |= WindowType::CriticalNotification;
}
return mask;
}
} // namespace KWin

View file

@ -11,7 +11,6 @@
#include "scripting.h"
// own
#include "clientmodel.h"
#include "dbuscall.h"
#include "desktopbackgrounditem.h"
#include "kwinquickeffect.h"
@ -19,6 +18,7 @@
#include "scripting_logging.h"
#include "scriptingutils.h"
#include "virtualdesktopmodel.h"
#include "windowmodel.h"
#include "windowthumbnailitem.h"
#include "workspace_wrapper.h"
@ -677,8 +677,8 @@ void KWin::Scripting::init()
qmlRegisterType<WindowThumbnailItem>("org.kde.kwin", 3, 0, "WindowThumbnailItem");
qmlRegisterType<DBusCall>("org.kde.kwin", 3, 0, "DBusCall");
qmlRegisterType<ScreenEdgeItem>("org.kde.kwin", 3, 0, "ScreenEdgeItem");
qmlRegisterType<ClientModel>("org.kde.kwin", 3, 0, "ClientModel");
qmlRegisterType<ClientFilterModel>("org.kde.kwin", 3, 0, "ClientFilterModel");
qmlRegisterType<WindowModel>("org.kde.kwin", 3, 0, "WindowModel");
qmlRegisterType<WindowFilterModel>("org.kde.kwin", 3, 0, "WindowFilterModel");
qmlRegisterType<VirtualDesktopModel>("org.kde.kwin", 3, 0, "VirtualDesktopModel");
qmlRegisterUncreatableType<KWin::QuickSceneView>("org.kde.kwin", 3, 0, "SceneView", QStringLiteral("Can't instantiate an object of type SceneView"));

View file

@ -0,0 +1,330 @@
/*
SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "windowmodel.h"
#include "core/output.h"
#include "core/outputbackend.h"
#include "virtualdesktops.h"
#include "window.h"
#include "workspace.h"
namespace KWin
{
WindowModel::WindowModel(QObject *parent)
: QAbstractListModel(parent)
{
connect(workspace(), &Workspace::windowAdded, this, &WindowModel::handleWindowAdded);
connect(workspace(), &Workspace::windowRemoved, this, &WindowModel::handleWindowRemoved);
m_windows = workspace()->allClientList();
for (Window *window : std::as_const(m_windows)) {
setupWindowConnections(window);
}
}
void WindowModel::markRoleChanged(Window *window, int role)
{
const QModelIndex row = index(m_windows.indexOf(window), 0);
Q_EMIT dataChanged(row, row, {role});
}
void WindowModel::setupWindowConnections(Window *window)
{
connect(window, &Window::desktopChanged, this, [this, window]() {
markRoleChanged(window, DesktopRole);
});
connect(window, &Window::outputChanged, this, [this, window]() {
markRoleChanged(window, OutputRole);
});
connect(window, &Window::activitiesChanged, this, [this, window]() {
markRoleChanged(window, ActivityRole);
});
}
void WindowModel::handleWindowAdded(Window *window)
{
beginInsertRows(QModelIndex(), m_windows.count(), m_windows.count());
m_windows.append(window);
endInsertRows();
setupWindowConnections(window);
}
void WindowModel::handleWindowRemoved(Window *window)
{
const int index = m_windows.indexOf(window);
Q_ASSERT(index != -1);
beginRemoveRows(QModelIndex(), index, index);
m_windows.removeAt(index);
endRemoveRows();
}
QHash<int, QByteArray> WindowModel::roleNames() const
{
return {
{Qt::DisplayRole, QByteArrayLiteral("display")},
{WindowRole, QByteArrayLiteral("window")},
{OutputRole, QByteArrayLiteral("output")},
{DesktopRole, QByteArrayLiteral("desktop")},
{ActivityRole, QByteArrayLiteral("activity")},
};
}
QVariant WindowModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() < 0 || index.row() >= m_windows.count()) {
return QVariant();
}
Window *window = m_windows[index.row()];
switch (role) {
case Qt::DisplayRole:
case WindowRole:
return QVariant::fromValue(window);
case OutputRole:
return QVariant::fromValue(window->output());
case DesktopRole:
return window->desktop();
case ActivityRole:
return window->activities();
default:
return QVariant();
}
}
int WindowModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_windows.count();
}
WindowFilterModel::WindowFilterModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
WindowModel *WindowFilterModel::windowModel() const
{
return m_windowModel;
}
void WindowFilterModel::setWindowModel(WindowModel *windowModel)
{
if (windowModel == m_windowModel) {
return;
}
m_windowModel = windowModel;
setSourceModel(m_windowModel);
Q_EMIT windowModelChanged();
}
QString WindowFilterModel::activity() const
{
return m_activity.value_or(QString());
}
void WindowFilterModel::setActivity(const QString &activity)
{
if (m_activity != activity) {
m_activity = activity;
Q_EMIT activityChanged();
invalidateFilter();
}
}
void WindowFilterModel::resetActivity()
{
if (m_activity.has_value()) {
m_activity.reset();
Q_EMIT activityChanged();
invalidateFilter();
}
}
VirtualDesktop *WindowFilterModel::desktop() const
{
return m_desktop;
}
void WindowFilterModel::setDesktop(VirtualDesktop *desktop)
{
if (m_desktop != desktop) {
m_desktop = desktop;
Q_EMIT desktopChanged();
invalidateFilter();
}
}
void WindowFilterModel::resetDesktop()
{
setDesktop(nullptr);
}
QString WindowFilterModel::filter() const
{
return m_filter;
}
void WindowFilterModel::setFilter(const QString &filter)
{
if (filter == m_filter) {
return;
}
m_filter = filter;
Q_EMIT filterChanged();
invalidateFilter();
}
QString WindowFilterModel::screenName() const
{
return m_output ? m_output->name() : QString();
}
void WindowFilterModel::setScreenName(const QString &screen)
{
Output *output = kwinApp()->outputBackend()->findOutput(screen);
if (m_output != output) {
m_output = output;
Q_EMIT screenNameChanged();
invalidateFilter();
}
}
void WindowFilterModel::resetScreenName()
{
if (m_output) {
m_output = nullptr;
Q_EMIT screenNameChanged();
invalidateFilter();
}
}
WindowFilterModel::WindowTypes WindowFilterModel::windowType() const
{
return m_windowType.value_or(WindowTypes());
}
void WindowFilterModel::setWindowType(WindowTypes windowType)
{
if (m_windowType != windowType) {
m_windowType = windowType;
Q_EMIT windowTypeChanged();
invalidateFilter();
}
}
void WindowFilterModel::resetWindowType()
{
if (m_windowType.has_value()) {
m_windowType.reset();
Q_EMIT windowTypeChanged();
invalidateFilter();
}
}
void WindowFilterModel::setMinimizedWindows(bool show)
{
if (m_showMinimizedWindows == show) {
return;
}
m_showMinimizedWindows = show;
invalidateFilter();
Q_EMIT minimizedWindowsChanged();
}
bool WindowFilterModel::minimizedWindows() const
{
return m_showMinimizedWindows;
}
bool WindowFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (!m_windowModel) {
return false;
}
const QModelIndex index = m_windowModel->index(sourceRow, 0, sourceParent);
if (!index.isValid()) {
return false;
}
const QVariant data = index.data();
if (!data.isValid()) {
// an invalid QVariant is valid data
return true;
}
Window *window = qvariant_cast<Window *>(data);
if (!window) {
return false;
}
if (m_activity.has_value()) {
if (!window->isOnActivity(*m_activity)) {
return false;
}
}
if (m_desktop) {
if (!window->isOnDesktop(m_desktop)) {
return false;
}
}
if (m_output) {
if (!window->isOnOutput(m_output)) {
return false;
}
}
if (m_windowType.has_value()) {
if (!(windowTypeMask(window) & *m_windowType)) {
return false;
}
}
if (!m_filter.isEmpty()) {
if (window->caption().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
if (window->windowRole().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
if (window->resourceName().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
if (window->resourceClass().contains(m_filter, Qt::CaseInsensitive)) {
return true;
}
return false;
}
if (!m_showMinimizedWindows) {
return !window->isMinimized();
}
return true;
}
WindowFilterModel::WindowTypes WindowFilterModel::windowTypeMask(Window *window) const
{
WindowTypes mask;
if (window->isNormalWindow()) {
mask |= WindowType::Normal;
} else if (window->isDialog()) {
mask |= WindowType::Dialog;
} else if (window->isDock()) {
mask |= WindowType::Dock;
} else if (window->isDesktop()) {
mask |= WindowType::Desktop;
} else if (window->isNotification()) {
mask |= WindowType::Notification;
} else if (window->isCriticalNotification()) {
mask |= WindowType::CriticalNotification;
}
return mask;
}
} // namespace KWin

View file

@ -19,38 +19,38 @@ namespace KWin
class Window;
class Output;
class ClientModel : public QAbstractListModel
class WindowModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
ClientRole = Qt::UserRole + 1,
WindowRole = Qt::UserRole + 1,
OutputRole,
DesktopRole,
ActivityRole
};
explicit ClientModel(QObject *parent = nullptr);
explicit WindowModel(QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
private:
void markRoleChanged(Window *client, int role);
void markRoleChanged(Window *window, int role);
void handleClientAdded(Window *client);
void handleClientRemoved(Window *client);
void setupClientConnections(Window *client);
void handleWindowAdded(Window *window);
void handleWindowRemoved(Window *window);
void setupWindowConnections(Window *window);
QList<Window *> m_clients;
QList<Window *> m_windows;
};
class ClientFilterModel : public QSortFilterProxyModel
class WindowFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(ClientModel *clientModel READ clientModel WRITE setClientModel NOTIFY clientModelChanged)
Q_PROPERTY(WindowModel *windowModel READ windowModel WRITE setWindowModel NOTIFY windowModelChanged)
Q_PROPERTY(QString activity READ activity WRITE setActivity RESET resetActivity NOTIFY activityChanged)
Q_PROPERTY(KWin::VirtualDesktop *desktop READ desktop WRITE setDesktop RESET resetDesktop NOTIFY desktopChanged)
Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged)
@ -70,10 +70,10 @@ public:
Q_DECLARE_FLAGS(WindowTypes, WindowType)
Q_FLAG(WindowTypes)
explicit ClientFilterModel(QObject *parent = nullptr);
explicit WindowFilterModel(QObject *parent = nullptr);
ClientModel *clientModel() const;
void setClientModel(ClientModel *clientModel);
WindowModel *windowModel() const;
void setWindowModel(WindowModel *windowModel);
QString activity() const;
void setActivity(const QString &activity);
@ -104,15 +104,15 @@ Q_SIGNALS:
void activityChanged();
void desktopChanged();
void screenNameChanged();
void clientModelChanged();
void windowModelChanged();
void filterChanged();
void windowTypeChanged();
void minimizedWindowsChanged();
private:
WindowTypes windowTypeMask(Window *client) const;
WindowTypes windowTypeMask(Window *window) const;
ClientModel *m_clientModel = nullptr;
WindowModel *m_windowModel = nullptr;
std::optional<QString> m_activity;
QPointer<Output> m_output;
QPointer<VirtualDesktop> m_desktop;