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 }