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 }