Warning, /plasma/kwin/src/plugins/overview/qml/main.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003     SPDX-FileCopyrightText: 2022 ivan tkachenko <me@ratijas.tk>
0004     SPDX-FileCopyrightText: 2023 Niccolò Venerandi <niccolo@venerandi.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 import QtQuick
0010 import Qt5Compat.GraphicalEffects
0011 import QtQuick.Layouts
0012 import org.kde.kirigami 2.20 as Kirigami
0013 import org.kde.kwin as KWinComponents
0014 import org.kde.kwin.private.effects
0015 import org.kde.milou as Milou
0016 import org.kde.plasma.components as PC3
0017 import org.kde.plasma.extras as PlasmaExtras
0018 import org.kde.kcmutils as KCM
0019 
0020 FocusScope {
0021     id: container
0022     focus: true
0023 
0024     readonly property QtObject effect: KWinComponents.SceneView.effect
0025     readonly property QtObject targetScreen: KWinComponents.SceneView.screen
0026 
0027     readonly property bool lightBackground: Math.max(Kirigami.Theme.backgroundColor.r,
0028                                                      Kirigami.Theme.backgroundColor.g,
0029                                                      Kirigami.Theme.backgroundColor.b) > 0.5
0030 
0031     property bool animationEnabled: false
0032     property bool organized: false
0033 
0034     property bool verticalDesktopBar: KWinComponents.Workspace.desktopGridHeight >= bar.desktopCount && KWinComponents.Workspace.desktopGridHeight != 1
0035     property bool anyDesktopBar: verticalDesktopBar || KWinComponents.Workspace.desktopGridHeight == 1
0036 
0037     // The values of overviewVal and gridVal might not be 0 on startup,
0038     // but we always want to animate from 0 to those values. So, we initially
0039     // always set them to 0 and bind their full values when the effect starts.
0040     // See start()
0041     property real overviewVal: 0
0042     property real gridVal: 0
0043 
0044     states: [
0045         State {
0046             name: "initial"
0047             PropertyChanges {
0048                 target: container
0049                 overviewVal: 0
0050                 gridVal: 0
0051             }
0052         },
0053         State {
0054             name: "grid"
0055             PropertyChanges {
0056                 target: container
0057                 overviewVal: 0
0058                 gridVal: 1
0059             }
0060         },
0061         State {
0062             name: "overview"
0063             PropertyChanges {
0064                 target: container
0065                 overviewVal: 1
0066                 gridVal: 0
0067             }
0068         },
0069         State {
0070             name: "partialOverview"
0071             PropertyChanges {
0072                 target: container
0073                 overviewVal: effect.overviewPartialActivationFactor
0074                 gridVal: 0
0075             }
0076         },
0077         State {
0078             name: "partialGrid"
0079             PropertyChanges {
0080                 target: container
0081                 overviewVal: 0
0082                 gridVal: effect.gridPartialActivationFactor
0083             }
0084         },
0085         State {
0086             name: "transition"
0087             PropertyChanges {
0088                 target: container
0089                 overviewVal: 1 - effect.transitionPartialActivationFactor
0090                 gridVal: effect.transitionPartialActivationFactor
0091             }
0092         }
0093     ]
0094     state: {
0095         // If the effect hasn't started, we remain on the initial state
0096         if (!organized) return "initial";
0097 
0098         // If a gesture is ongoing, we use a partial state
0099         if (effect.overviewGestureInProgress) return "partialOverview";
0100         if (effect.gridGestureInProgress) return "partialGrid";
0101         if (effect.transitionGestureInProgress) return "transition";
0102 
0103         // If either the overview or grid gestures are completed, either
0104         // by a touchpad/touchscreen gesture or through a shortcut, we use
0105         // that state
0106         if (effect.overviewPartialActivationFactor === 1) return "overview";
0107         if (effect.gridPartialActivationFactor === 1) return "grid";
0108 
0109         // If neither is active, we are in the initial state.
0110         if (effect.overviewPartialActivationFactor + effect.gridPartialActivationFactor === 0) return "initial";
0111 
0112         // If we are inbetween a state but no gesture is going on, we snap to
0113         // the closest state
0114         if (overviewVal >= 0.5) return "overview";
0115         if (gridVal >= 0.5) return "grid";
0116         return "initial";
0117     }
0118     transitions: Transition {
0119         to: "initial, grid, overview"
0120         NumberAnimation {
0121             duration: effect.animationDuration
0122             properties: "gridVal, overviewVal"
0123             easing.type: Easing.OutCubic
0124         }
0125     }
0126 
0127     function switchTo(desktop) {
0128         KWinComponents.Workspace.currentDesktop = desktop;
0129         effect.deactivate();
0130     }
0131 
0132     function selectNext(direction) {
0133         if (effect.searchText !== "") return false;
0134         let currentIndex = 0
0135         for (let i = 0; i < allDesktopHeaps.count; i++) {
0136             if (allDesktopHeaps.itemAt(i).current) {
0137                 currentIndex = i;
0138                 break;
0139             }
0140         }
0141         let x = currentIndex % container.columns;
0142         let y = Math.floor(currentIndex / container.columns);
0143 
0144         // the direction we move in is the opposite of the window to select
0145         // i.e pressing left should select the rightmost window on the desktop
0146         // to the left
0147         let invertedDirection;
0148         switch(direction) {
0149             case WindowHeap.Direction.Up:
0150                 y--;
0151                 invertedDirection = WindowHeap.Direction.Down;
0152                 break;
0153             case WindowHeap.Direction.Down:
0154                 y++
0155                 invertedDirection = WindowHeap.Direction.Up;
0156                 break;
0157             case WindowHeap.Direction.Left:
0158                 x--;
0159                 invertedDirection = WindowHeap.Direction.Right;
0160                 break;
0161             case WindowHeap.Direction.Right:
0162                 x++;
0163                 invertedDirection = WindowHeap.Direction.Left;
0164                 break;
0165         }
0166 
0167         if (x < 0 || x >= container.columns) {
0168             return false;
0169         }
0170         if (y < 0 || y >= container.rows) {
0171             return false;
0172         }
0173         let newIndex = y * container.columns + x;
0174 
0175         KWinComponents.Workspace.currentDesktop = allDesktopHeaps.itemAt(newIndex).desktop
0176         allDesktopHeaps.itemAt(newIndex).nestedHeap.focus = true
0177         allDesktopHeaps.itemAt(newIndex).selectLastItem(invertedDirection);
0178         return true;
0179     }
0180 
0181     Keys.onPressed: (event) => {
0182         if (event.key === Qt.Key_Escape) {
0183             if (effect.searchText !== "") {
0184                 effect.searchText = ""
0185             } else {
0186                 effect.deactivate();
0187             }
0188         } else if (event.key === Qt.Key_Plus || event.key === Qt.Key_Equal) {
0189             desktopModel.create(desktopModel.rowCount());
0190         } else if (event.key === Qt.Key_Minus) {
0191             desktopModel.remove(desktopModel.rowCount() - 1);
0192         } else if (event.key >= Qt.Key_F1 && event.key <= Qt.Key_F12) {
0193             const desktopId = event.key - Qt.Key_F1;
0194             if (desktopId < allDesktopHeaps.count) {
0195                 switchTo(allDesktopHeaps.itemAt(desktopId).desktop);
0196             }
0197         } else if (event.key >= Qt.Key_0 && event.key <= Qt.Key_9) {
0198             const desktopId = event.key === Qt.Key_0 ? 9 : (event.key - Qt.Key_1);
0199             if (desktopId < allDesktopHeaps.count) {
0200                 switchTo(allDesktopHeaps.itemAt(desktopId).desktop);
0201             }
0202         } else if (event.key === Qt.Key_Up) {
0203             event.accepted = selectNext(WindowHeap.Direction.Up);
0204             if (!event.accepted) {
0205                 let view = effect.getView(Qt.TopEdge)
0206                 if (view) {
0207                     effect.activateView(view)
0208                 }
0209             }
0210         } else if (event.key === Qt.Key_Down) {
0211             event.accepted = selectNext(WindowHeap.Direction.Down);
0212             if (!event.accepted) {
0213                 let view = effect.getView(Qt.BottomEdge)
0214                 if (view) {
0215                     effect.activateView(view)
0216                 }
0217             }
0218         } else if (event.key === Qt.Key_Left) {
0219             event.accepted = selectNext(WindowHeap.Direction.Left);
0220             if (!event.accepted) {
0221                 let view = effect.getView(Qt.LeftEdge)
0222                 if (view) {
0223                     effect.activateView(view)
0224                 }
0225             }
0226         } else if (event.key === Qt.Key_Right) {
0227             event.accepted = selectNext(WindowHeap.Direction.Right);
0228             if (!event.accepted) {
0229                 let view = effect.getView(Qt.RightEdge)
0230                 if (view) {
0231                     effect.activateView(view)
0232                 }
0233             }
0234         } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Space) {
0235             for (let i = 0; i < allDesktopHeaps.count; i++) {
0236                 if (allDesktopHeaps.itemAt(i).current) {
0237                     switchTo(allDesktopHeaps.itemAt(i).desktop)
0238                     break;
0239                 }
0240             }
0241         }
0242     }
0243     Keys.priority: Keys.AfterItem
0244 
0245     Item {
0246         width: backgroundItem.width
0247         height: backgroundItem.height
0248         KWinComponents.DesktopBackground {
0249             id: backgroundItem
0250             activity: KWinComponents.Workspace.currentActivity
0251             desktop: KWinComponents.Workspace.currentDesktop
0252             outputName: targetScreen.name
0253             visible: false
0254         }
0255         FastBlur {
0256             anchors.fill: parent
0257             source: backgroundItem
0258             radius: 64
0259         }
0260     }
0261 
0262     Rectangle {
0263         id: underlay
0264         anchors.fill: parent
0265         opacity: 0.7
0266         color: Kirigami.Theme.backgroundColor
0267 
0268         TapHandler {
0269             onTapped: effect.deactivate();
0270         }
0271     }
0272 
0273     Item {
0274         id: desktopBar
0275         visible: container.anyDesktopBar
0276 
0277         // (overviewVal, gridVal) represents the state of the overview
0278         // in a 2D coordinate plane. Math.atan2 returns the angle between
0279         // the x axis and that point. By using this to set the opacity,
0280         // we can have an opaque desktopBar when the point moves from
0281         // the origin to the "overviewVal" direction, which has angle pi/2,
0282         // and a transparent desktopBar when the point moves from
0283         // the origin to the "gridVal" direction, which has angle 0,
0284         // whilst still animating when the point moves from overviewVal to
0285         // gridVal too.
0286         opacity: Math.atan2(overviewVal, gridVal) / Math.PI * 2
0287 
0288         anchors.top: parent.top
0289         anchors.left: parent.left
0290         anchors.right: container.verticalDesktopBar ? undefined : parent.right
0291         anchors.bottom: container.verticalDesktopBar ? parent.bottom : undefined
0292         height: bar.implicitHeight + 2 * Kirigami.Units.smallSpacing
0293         width: bar.implicitWidth + 2 * Kirigami.Units.smallSpacing
0294 
0295         DesktopBar {
0296             id: bar
0297             anchors.fill: parent
0298             windowModel: stackModel
0299             desktopModel: desktopModel
0300             verticalDesktopBar: container.verticalDesktopBar
0301             selectedDesktop: KWinComponents.Workspace.currentDesktop
0302             heap: allDesktopHeaps.currentHeap
0303         }
0304     }
0305 
0306     Item {
0307         id: topBar
0308         opacity: desktopBar.opacity
0309         anchors.left: container.verticalDesktopBar ? desktopBar.right : parent.left
0310         anchors.right: parent.right
0311         anchors.top: container.verticalDesktopBar || !container.anyDesktopBar ? parent.top : desktopBar.bottom
0312         anchors.topMargin: Kirigami.Units.largeSpacing
0313         height: searchField.height + 1 * Kirigami.Units.largeSpacing
0314 
0315         PlasmaExtras.SearchField {
0316             id: searchField
0317             anchors.centerIn: parent
0318             width: Math.min(parent.width, 20 * Kirigami.Units.gridUnit)
0319             focus: enabled
0320             readOnly: gridVal == 1
0321             onReadOnlyChanged: {
0322                 text = ""
0323                 effect.searchText = ""
0324                 effect.searchTextChanged()
0325             }
0326             Keys.priority: Keys.BeforeItem
0327             Keys.forwardTo: text && (allDesktopHeaps.currentHeap.count === 0 || !effect.filterWindows) ? searchResults : allDesktopHeaps.currentHeap
0328             text: effect.searchText
0329             // not onTextEdited so that the UI always stays in sync
0330             onTextChanged: {
0331                 effect.searchText = text;
0332                 allDesktopHeaps.currentHeap.resetSelected();
0333                 allDesktopHeaps.currentHeap.selectNextItem(WindowHeap.Direction.Down);
0334                 searchField.focus = true;
0335             }
0336         }
0337     }
0338 
0339     property var currentGeometry: targetScreen.geometry
0340 
0341     // These are the minimum position of maximum size of the desktop preview in the overview
0342     property int minX: Kirigami.Units.largeSpacing + (container.verticalDesktopBar ? desktopBar.width : 0)
0343     property int minY: Kirigami.Units.largeSpacing + topBar.height + (container.verticalDesktopBar || !container.anyDesktopBar ? 0 : desktopBar.height)
0344     property int maxWidth: currentGeometry.width - minX - Kirigami.Units.gridUnit * 2
0345     property int maxHeight: currentGeometry.height - minY - Kirigami.Units.gridUnit * 2
0346 
0347     property int desktops: Math.max(bar.desktopCount, 2)
0348     property int columns: Math.ceil(desktops / rows)
0349     property int rows: KWinComponents.Workspace.desktopGridHeight
0350 
0351     // The desktop might shuffle around as soon as it's
0352     // created since the rows/columns are updated after
0353     // the desktop is added. We don't want to see that.
0354     property bool desktopJustCreated: false
0355     onDesktopsChanged: {
0356         desktopJustCreated = true
0357         startTimer.running = true
0358     }
0359 
0360     Timer {
0361         id: startTimer
0362         interval: effect.animationDuration
0363         running: false
0364         onTriggered: desktopJustCreated = false
0365     }
0366 
0367     Item {
0368         id: desktopGrid
0369         anchors.fill: parent
0370         property var dndManagerStore: ({})
0371 
0372         ColumnLayout {
0373             x: Math.round(parent.width / 2) + Math.round(parent.width / 8)
0374             width: Math.round(parent.width / 2) - Math.round(parent.width / 8) * 2
0375             anchors.verticalCenter: parent.verticalCenter
0376             visible: bar.desktopCount === 1
0377             opacity: gridVal
0378             spacing: Kirigami.Units.largeSpacing
0379 
0380             Kirigami.PlaceholderMessage {
0381                 text: i18ndc("kwin", "@info:placeholder", "No other Virtual Desktops to show")
0382                 icon.name: "virtual-desktops-symbolic"
0383             }
0384 
0385             PC3.Button {
0386                 Layout.alignment: Qt.AlignHCenter
0387                 text: i18ndc("kwin", "@action:button", "Add Virtual Desktop")
0388                 icon.name: "list-add-symbolic"
0389                 onClicked: desktopModel.create(desktopModel.rowCount())
0390             }
0391 
0392             PC3.Button {
0393                 Layout.alignment: Qt.AlignHCenter
0394                 text: i18ndc("kwin", "@action:button", "Configure Virtual Desktops…")
0395                 icon.name: "preferences-virtual-desktops"
0396                 onClicked: {
0397                     KCM.KCMLauncher.openSystemSettings("kcm_kwin_virtualdesktops")
0398                     effect.deactivate();
0399                 }
0400             }
0401 
0402         }
0403 
0404 
0405         Repeater {
0406             id: allDesktopHeaps
0407             model: desktopModel
0408 
0409             property Item currentHeap
0410             property Item currentBackgroundItem
0411 
0412             Item {
0413                 id: mainBackground
0414 
0415                 visible: gridVal > 0 || nearCurrent
0416                 anchors.fill: parent
0417                 property bool shouldBeVisibleInOverview: !(effect.searchText.length > 0 && current) || (heap.count !== 0 && effect.filterWindows)
0418                 opacity: 1 - overviewVal * (shouldBeVisibleInOverview ? 0 : 1)
0419 
0420                 function selectLastItem(direction) {
0421                     heap.selectLastItem(direction);
0422                 }
0423 
0424 
0425                 required property QtObject desktop
0426                 required property int index
0427                 readonly property bool current: KWinComponents.Workspace.currentDesktop === desktop
0428                 readonly property bool nearCurrent: Math.abs(deltaColumn) <= 1 && Math.abs(deltaRow) <= 1
0429                 readonly property var nestedHeap: heap
0430 
0431                 z: dragActive ? 1 : 0
0432                 readonly property bool dragActive: heap.dragActive || dragHandler.active
0433 
0434                 property int gridSize: Math.max(rows, columns)
0435                 property real row: (index - column) / columns
0436                 property real column: index % columns
0437                 // deltaX and deltaY are used to move all the desktops together to 1:1 animate the
0438                 // switching between different desktops
0439                 property real deltaX: (!current ? effect.desktopOffset.x :
0440                                        column == 0 ? Math.max(0, effect.desktopOffset.x) :
0441                                        column == columns - 1 ? Math.min(0, effect.desktopOffset.x) :
0442                                        effect.desktopOffset.x)
0443                 property real deltaY: (!current ? effect.desktopOffset.y :
0444                                        row == 0 ? Math.max(0, effect.desktopOffset.y) :
0445                                        row == rows - 1 ? Math.min(0, effect.desktopOffset.y) :
0446                                        effect.desktopOffset.y)
0447                 // deltaColumn and deltaRows are the difference between the column/row of this desktop
0448                 // compared to the column/row of the active one
0449                 property real deltaColumn: column - allDesktopHeaps.currentBackgroundItem.column - deltaX
0450                 property real deltaRow: row - allDesktopHeaps.currentBackgroundItem.row - deltaY
0451 
0452                 Behavior on deltaColumn {
0453                     enabled: overviewVal > 0 && !container.desktopJustCreated
0454                     NumberAnimation {
0455                         duration: effect.animationDuration
0456                         easing.type: Easing.OutCubic
0457                     }
0458                 }
0459                 Behavior on deltaRow {
0460                     enabled: overviewVal > 0 && !container.desktopJustCreated
0461                     NumberAnimation {
0462                         duration: effect.animationDuration
0463                         easing.type: Easing.OutCubic
0464                     }
0465                 }
0466 
0467                 // Note that transforms should be read from the last one to the first one
0468                 transform: [
0469                     // Scales down further, still in grid, to have some gaps between
0470                     // the desktops.
0471                     Scale {
0472                         origin.x: width / 2
0473                         origin.y: height / 2
0474                         xScale: 1 - 0.02 * gridVal
0475                         yScale: xScale
0476                     },
0477                     // Scales down the desktops so that they do not overlap in the grid
0478                     Scale {
0479                         id: gridScale
0480                         xScale: 1 + (1 / gridSize - 1) * gridVal
0481                         yScale: xScale
0482                     },
0483                     // Further little translation in the grids to align the elements
0484                     // to the center of their cell
0485                     Translate{
0486                         x: (gridSize / columns - 1) * (width / gridSize) / 2 * gridVal
0487                         y: (gridSize / rows - 1) * (height / gridSize) / 2 * gridVal
0488                     },
0489                     // When in desktop grid, translates the desktop so that the whole
0490                     // grid fits in the view
0491                     Translate {
0492                         x: column * (width / columns) * gridVal
0493                         y: row * (height / rows) * gridVal
0494                     },
0495                     // Initially places transition desktops in a grid around the current one,
0496                     // and moves them slighly to avoid overlapping the UI
0497                     Translate {
0498                         x: minX * 0.5 * overviewVal + deltaColumn * width * (1 - gridVal)
0499                         y: minY * 0.5 * overviewVal + deltaRow * height * (1 - gridVal)
0500                     }
0501                 ]
0502 
0503                 Item {
0504                     id: backgroundArea
0505                     property real sizeAdjust: Math.min(maxWidth / parent.width, maxHeight / parent.height)
0506                     width: parent.width * (1 + (sizeAdjust - 1) * overviewVal)
0507                     height: parent.height * (1 + (sizeAdjust - 1) * overviewVal)
0508                     x: parent.width / 2 - width / 2
0509                     y: parent.height / 2 - height / 2
0510                     KWinComponents.DesktopBackground {
0511                         id: desktopElement
0512                         anchors.fill: parent
0513                         anchors.margins: gridVal !== 0 ? Math.round(mainBackground.current * gridVal * (1.5 / gridScale.xScale)) : 0
0514                         activity: KWinComponents.Workspace.currentActivity
0515                         desktop: KWinComponents.Workspace.currentDesktop
0516                         outputName: targetScreen.name
0517                         visible: false
0518                     }
0519 
0520                     Kirigami.ShadowedTexture {
0521                         anchors.fill: parent
0522 
0523                         color: Kirigami.Theme.highlightColor
0524                         source: desktopElement
0525 
0526                         radius: Kirigami.Units.largeSpacing * 2 * (overviewVal + gridVal * 2)
0527 
0528                         shadow {
0529                             size: Kirigami.Units.gridUnit * 2
0530                             color: Qt.rgba(0, 0, 0, 0.3)
0531                             yOffset: 3
0532                         }
0533                     }
0534 
0535                     DropArea {
0536                         anchors.fill: parent
0537                         onEntered: (drag) => {
0538                             drag.accepted = true;
0539                         }
0540                         onDropped: (drop) => {
0541                             drop.accepted = true;
0542                             if (drop.keys.includes("kwin-desktop")) {
0543                                 // dragging a desktop as a whole
0544                                 if (drag.source === mainBackground) {
0545                                     drop.action = Qt.IgnoreAction;
0546                                     return;
0547                                 }
0548                                 effect.swapDesktops(drag.source.desktop, desktop);
0549                             } else {
0550                                 // dragging a KWin::Window
0551                                 if (drag.source.desktops.length === 0 || drag.source.desktops.indexOf(mainBackground.desktop) !== -1) {
0552                                     drop.action = Qt.IgnoreAction;
0553                                     return;
0554                                 }
0555                                 drag.source.desktops = [mainBackground.desktop];
0556                             }
0557                         }
0558                     }
0559                     Connections {
0560                         target: effect
0561                         function onItemDroppedOutOfScreen(globalPos, item, screen) {
0562                             if (screen !== targetScreen) {
0563                                 return;
0564                             }
0565                             const pos = screen.mapFromGlobal(globalPos);
0566                             if (!mainBackground.contains(mainBackground.mapFromItem(null, pos.x, pos.y))) {
0567                                 return;
0568                             }
0569                             item.client.desktops = [mainBackground.desktop];
0570                         }
0571                     }
0572                     DragHandler {
0573                         id: dragHandler
0574                         target: heap
0575                         enabled: gridVal !== 0
0576                         grabPermissions: PointerHandler.ApprovesTakeOverByHandlersOfSameType
0577                         onActiveChanged: {
0578                             if (!active) {
0579                                 heap.Drag.drop();
0580                                 Qt.callLater(heap.resetPosition)
0581                             }
0582                         }
0583                     }
0584 
0585                     MouseArea {
0586                         anchors.fill: heap
0587                         acceptedButtons: Qt.NoButton
0588                         cursorShape: dragHandler.active ? Qt.ClosedHandCursor : Qt.ArrowCursor
0589                     }
0590                 }
0591 
0592                 WindowHeap {
0593                     id: heap
0594                     width: parent.width * (1 + (backgroundArea.sizeAdjust - 1))
0595                     height: parent.height * (1 + (backgroundArea.sizeAdjust - 1))
0596                     x: parent.width / 2 - width / 2
0597                     y: parent.height / 2 - height / 2
0598 
0599                     function resetPosition() {
0600                         x = parent.width / 2 - width / 2;
0601                         y = parent.height / 2 - height / 2;
0602                     }
0603                     z: 9999
0604                     Drag.active: dragHandler.active
0605                     Drag.proposedAction: Qt.MoveAction
0606                     Drag.supportedActions: Qt.MoveAction
0607                     Drag.source: mainBackground
0608                     Drag.hotSpot: Qt.point(width * 0.5, height * 0.5)
0609                     Drag.keys: ["kwin-desktop"]
0610 
0611                     layout.mode: effect.layout
0612                     focus: current
0613                     padding: Kirigami.Units.largeSpacing
0614                     animationDuration: effect.animationDuration
0615                     animationEnabled:  (gridVal !== 0 || mainBackground.current) && organized
0616                     organized: container.state !== "initial"
0617                     dndManagerStore: desktopGrid.dndManagerStore
0618                     Keys.priority: Keys.AfterItem
0619                     Keys.forwardTo: [searchResults, searchField]
0620                     model: KWinComponents.WindowFilterModel {
0621                         activity: KWinComponents.Workspace.currentActivity
0622                         desktop: mainBackground.desktop
0623                         screenName: targetScreen.name
0624                         windowModel: stackModel
0625                         filter: effect.searchText
0626                         minimizedWindows: !effect.ignoreMinimized
0627                         windowType: ~KWinComponents.WindowFilterModel.Dock &
0628                                     ~KWinComponents.WindowFilterModel.Desktop &
0629                                     ~KWinComponents.WindowFilterModel.Notification &
0630                                     ~KWinComponents.WindowFilterModel.CriticalNotification
0631                     }
0632                     delegate: WindowHeapDelegate {
0633                         windowHeap: heap
0634 
0635                         // This is preferable over using gestureInProgress values since gridVal and
0636                         // overviewVal are animated even after the gesture ends, and since the partial
0637                         // activation factor follows those two values, this results in a more
0638                         // fluent animation.
0639                         gestureInProgress: !Number.isInteger(gridVal) || !Number.isInteger(overviewVal)
0640 
0641                         partialActivationFactor: container.overviewVal + container.gridVal * effect.organizedGrid
0642 
0643                         targetScale: {
0644                             if (!container.anyDesktopBar) return targetScale;
0645                             if (overviewVal != 1) return targetScale;
0646                             let coordinate = container.verticalDesktopBar ? 'x' : 'y'
0647                             if (!activeDragHandler.active) {
0648                                 return targetScale; // leave it alone, so it won't affect transitions before they start
0649                             }
0650                             var localPressPosition = activeDragHandler.centroid.scenePressPosition[coordinate] - heap.layout.Kirigami.ScenePosition[coordinate];
0651                             if (localPressPosition === 0) {
0652                                 return 0.1;
0653                             } else {
0654                                 var localPosition = activeDragHandler.centroid.scenePosition[coordinate] - heap.layout.Kirigami.ScenePosition[coordinate];
0655                                 return Math.max(0.1, Math.min(localPosition / localPressPosition, 1));
0656                             }
0657                         }
0658 
0659                         opacity: 1 - downGestureProgress
0660                         onDownGestureTriggered: window.closeWindow()
0661                         TapHandler {
0662                             acceptedPointerTypes: PointerDevice.Generic | PointerDevice.Pen
0663                             acceptedButtons: Qt.MiddleButton | Qt.RightButton
0664                             onTapped: (eventPoint, button) => {
0665                                 if (button === Qt.MiddleButton) {
0666                                     window.closeWindow();
0667                                 } else if (button === Qt.RightButton) {
0668                                     if (window.desktops.length > 0) {
0669                                         window.desktops = [];
0670                                     } else {
0671                                         window.desktops = [mainBackground.desktop];
0672                                     }
0673                                 }
0674                             }
0675                         }
0676                     }
0677                     onActivated: effect.deactivate()
0678                 }
0679                 TapHandler {
0680                     acceptedButtons: Qt.LeftButton
0681                     onTapped: {
0682                         KWinComponents.Workspace.currentDesktop = mainBackground.desktop;
0683                         container.effect.deactivate();
0684                     }
0685                 }
0686 
0687                 onCurrentChanged: {
0688                     if (current) {
0689                         allDesktopHeaps.currentHeap = heap;
0690                         allDesktopHeaps.currentBackgroundItem = mainBackground;
0691                     }
0692                 }
0693                 Component.onCompleted: {
0694                     if (current) {
0695                         allDesktopHeaps.currentHeap = heap;
0696                         allDesktopHeaps.currentBackgroundItem = mainBackground;
0697                     }
0698                     startTimer.running = true
0699                 }
0700             }
0701 
0702         }
0703 
0704     }
0705 
0706     Loader {
0707         id: searchResults
0708         active: effect.searchText.length > 0 && (allDesktopHeaps.currentHeap.count === 0 || !effect.filterWindows)
0709         anchors.left: container.verticalDesktopBar ? desktopBar.right : parent.left
0710         anchors.right: parent.right
0711         anchors.bottom: parent.bottom
0712         anchors.top: topBar.bottom
0713 
0714         sourceComponent: Item {
0715             width: parent.width
0716             height: parent.height - topBar.height
0717             opacity: overviewVal
0718 
0719             PlasmaExtras.PlaceholderMessage {
0720                 id: placeholderMessage
0721                 visible: allDesktopHeaps.currentHeap.count === 0 && effect.filterWindows
0722                 anchors.top: parent.top
0723                 anchors.horizontalCenter: parent.horizontalCenter
0724                 text: i18ndc("kwin", "@info:placeholder", "No matching windows")
0725             }
0726 
0727             Milou.ResultsView {
0728                 id: milouView
0729                 anchors.bottom: parent.bottom
0730                 anchors.horizontalCenter: parent.horizontalCenter
0731                 width: parent.width / 2
0732                 height: effect.filterWindows ? parent.height - placeholderMessage.height - Kirigami.Units.largeSpacing : parent.height - Kirigami.Units.largeSpacing
0733                 queryString: effect.searchText
0734 
0735                 onActivated: {
0736                     effect.deactivate();
0737                 }
0738             }
0739 
0740             Keys.forwardTo: milouView
0741         }
0742 
0743         Keys.forwardTo: item
0744     }
0745 
0746     Repeater {
0747         model: KWinComponents.WindowFilterModel {
0748             desktop: KWinComponents.Workspace.currentDesktop
0749             screenName: targetScreen.name
0750             windowModel: stackModel
0751             windowType: KWinComponents.WindowFilterModel.Dock
0752         }
0753 
0754         KWinComponents.WindowThumbnail {
0755             id: windowThumbnail
0756             visible: !model.window.hidden && opacity > 0
0757             wId: model.window.internalId
0758             x: model.window.x - targetScreen.geometry.x
0759             y: model.window.y - targetScreen.geometry.y
0760             z: model.window.stackingOrder
0761             width: model.window.width
0762             height: model.window.height
0763             opacity: 1 - (gridVal + overviewVal)
0764         }
0765     }
0766 
0767     KWinComponents.WindowModel {
0768         id: stackModel
0769     }
0770 
0771     KWinComponents.VirtualDesktopModel {
0772         id: desktopModel
0773     }
0774 
0775     Component.onCompleted: {
0776         // The following line unbinds the verticalDesktopBar, meaning that it
0777         // won't react to changes in number of desktops or rows. This is beacuse we
0778         // don't want the desktop bar changing screenside whilst the user is
0779         // interacting with it, e.g. by adding desktops
0780         container.verticalDesktopBar = container.verticalDesktopBar
0781         organized = true
0782     }
0783 }