Warning, /plasma/kwin/src/plugins/private/qml/WindowHeapDelegate.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 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 import QtQuick 0009 import QtQuick.Window 0010 import Qt5Compat.GraphicalEffects 0011 import org.kde.kirigami 2.20 as Kirigami 0012 import org.kde.kwin as KWinComponents 0013 import org.kde.kwin.private.effects 0014 import org.kde.plasma.components 3.0 as PC3 0015 import org.kde.plasma.extras as PlasmaExtras 0016 import org.kde.ksvg 1.0 as KSvg 0017 0018 Item { 0019 id: thumb 0020 0021 required property QtObject window 0022 required property int index 0023 required property Item windowHeap 0024 0025 readonly property bool selected: windowHeap.selectedIndex === index 0026 property real partialActivationFactor: effect.partialActivationFactor 0027 property bool gestureInProgress: effect.gestureInProgress 0028 0029 // no desktops is a special value which means "All Desktops" 0030 readonly property bool presentOnCurrentDesktop: !window.desktops.length || window.desktops.indexOf(KWinComponents.Workspace.currentDesktop) !== -1 0031 readonly property bool initialHidden: window.minimized || !presentOnCurrentDesktop 0032 readonly property bool activeHidden: { 0033 if (window.skipSwitcher) { 0034 return true; 0035 } else if (windowHeap.showOnly === "activeClass") { 0036 if (!KWinComponents.Workspace.activeWindow) { 0037 return true; 0038 } else { 0039 return KWinComponents.Workspace.activeWindow.resourceName !== window.resourceName; 0040 } 0041 } else { 0042 return windowHeap.showOnly.length !== 0 0043 && windowHeap.showOnly.indexOf(window.internalId) === -1; 0044 } 0045 } 0046 0047 // Show a close button on this thumbnail 0048 property bool closeButtonVisible: true 0049 // Show a text label under this thumbnail 0050 property bool windowTitleVisible: true 0051 0052 // Same as for window heap 0053 property bool animationEnabled: false 0054 0055 //scale up and down the whole thumbnail without affecting layouting 0056 property real targetScale: 1.0 0057 0058 property DragManager activeDragHandler: dragHandler 0059 0060 // Swipe down gesture by touch, in some effects will close the window 0061 readonly property alias downGestureProgress: touchDragHandler.downGestureProgress 0062 signal downGestureTriggered() 0063 0064 // "normal" | "pressed" | "drag" | "reparenting" 0065 property string substate: "normal" 0066 0067 state: { 0068 if (thumb.gestureInProgress) { 0069 return "partial"; 0070 } 0071 if (thumb.partialActivationFactor > 0.5 && (cell.isReady || activeHidden)) { 0072 return activeHidden ? "active-hidden" : `active-${substate}`; 0073 } 0074 return initialHidden ? "initial-hidden" : "initial"; 0075 } 0076 0077 visible: opacity > 0 0078 z: (activeDragHandler.active || returning.running) ? 1000 0079 : window.stackingOrder * (presentOnCurrentDesktop ? 1 : 0.001) 0080 0081 function restoreDND(oldGlobalRect: rect) { 0082 thumbSource.restoreDND(oldGlobalRect); 0083 } 0084 0085 component TweenBehavior : Behavior { 0086 enabled: thumb.state === "active-normal" && thumb.windowHeap.animationEnabled && thumb.animationEnabled && !thumb.activeDragHandler.active 0087 NumberAnimation { 0088 duration: thumb.windowHeap.animationDuration 0089 easing.type: Easing.InOutCubic 0090 } 0091 } 0092 0093 TweenBehavior on x {} 0094 TweenBehavior on y {} 0095 TweenBehavior on width {} 0096 TweenBehavior on height {} 0097 0098 KWinComponents.WindowThumbnail { 0099 id: thumbSource 0100 wId: thumb.window.internalId 0101 0102 Drag.proposedAction: Qt.MoveAction 0103 Drag.supportedActions: Qt.MoveAction 0104 Drag.source: thumb.window 0105 Drag.hotSpot: Qt.point( 0106 thumb.activeDragHandler.centroid.pressPosition.x * thumb.targetScale, 0107 thumb.activeDragHandler.centroid.pressPosition.y * thumb.targetScale) 0108 Drag.keys: ["kwin-window"] 0109 0110 onXChanged: effect.checkItemDraggedOutOfScreen(thumbSource) 0111 onYChanged: effect.checkItemDraggedOutOfScreen(thumbSource) 0112 0113 function saveDND() { 0114 const oldGlobalRect = mapToItem(null, 0, 0, width, height); 0115 thumb.windowHeap.saveDND(thumb.window.internalId, oldGlobalRect); 0116 } 0117 function restoreDND(oldGlobalRect: rect) { 0118 thumb.substate = "reparenting"; 0119 0120 const newGlobalRect = mapFromItem(null, oldGlobalRect); 0121 0122 x = newGlobalRect.x; 0123 y = newGlobalRect.y; 0124 width = newGlobalRect.width; 0125 height = newGlobalRect.height; 0126 0127 thumb.substate = "normal"; 0128 } 0129 function deleteDND() { 0130 thumb.windowHeap.deleteDND(thumb.window.internalId); 0131 } 0132 0133 // Not using FrameSvg hover element intentionally for stylistic reasons 0134 Rectangle { 0135 border.width: Kirigami.Units.largeSpacing 0136 border.color: Kirigami.Theme.highlightColor 0137 anchors.fill: parent 0138 anchors.margins: -border.width 0139 radius: border.width 0140 color: "transparent" 0141 visible: !thumb.windowHeap.dragActive && (hoverHandler.hovered || (thumb.selected && Window.window.activeFocusItem)) && windowHeap.effectiveOrganized 0142 } 0143 0144 MouseArea { 0145 anchors.fill: parent 0146 acceptedButtons: Qt.NoButton 0147 cursorShape: thumb.activeDragHandler.active ? Qt.ClosedHandCursor : Qt.ArrowCursor 0148 } 0149 } 0150 0151 PC3.Label { 0152 anchors.fill: thumbSource 0153 horizontalAlignment: Text.AlignHCenter 0154 verticalAlignment: Text.AlignVCenter 0155 text: i18nd("kwin", "Drag Down To Close") 0156 opacity: thumbSource.opacity 0157 visible: !thumb.activeHidden && touchDragHandler.active 0158 } 0159 0160 Kirigami.Icon { 0161 id: icon 0162 width: Kirigami.Units.iconSizes.large 0163 height: Kirigami.Units.iconSizes.large 0164 source: thumb.window.icon 0165 anchors.horizontalCenter: thumbSource.horizontalCenter 0166 anchors.bottom: thumbSource.bottom 0167 anchors.bottomMargin: -Math.round(height / 4) 0168 visible: !thumb.activeHidden && !activeDragHandler.active 0169 0170 0171 PlasmaExtras.ShadowedLabel { 0172 id: caption 0173 visible: thumb.windowTitleVisible 0174 width: cell.width 0175 maximumLineCount: 1 0176 anchors.top: parent.bottom 0177 anchors.horizontalCenter: parent.horizontalCenter 0178 elide: Text.ElideRight 0179 text: thumb.window.caption 0180 textFormat: Text.PlainText 0181 horizontalAlignment: Text.AlignHCenter 0182 verticalAlignment: Text.AlignVCenter 0183 } 0184 } 0185 0186 ExpoCell { 0187 id: cell 0188 layout: windowHeap.layout 0189 enabled: !thumb.activeHidden 0190 naturalX: thumb.window.x 0191 naturalY: thumb.window.y 0192 naturalWidth: thumb.window.width 0193 naturalHeight: thumb.window.height 0194 persistentKey: thumb.window.internalId 0195 bottomMargin: icon.height / 4 + (thumb.windowTitleVisible ? caption.height : 0) 0196 property bool isReady: width !== 0 && height !== 0 0197 } 0198 0199 states: [ 0200 State { 0201 name: "initial" 0202 PropertyChanges { 0203 target: thumb 0204 x: thumb.window.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.x : 0) 0205 y: thumb.window.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.y : 0) 0206 width: thumb.window.width 0207 height: thumb.window.height 0208 } 0209 PropertyChanges { 0210 target: thumbSource 0211 x: 0 0212 y: 0 0213 width: thumb.window.width 0214 height: thumb.window.height 0215 } 0216 PropertyChanges { 0217 target: icon 0218 opacity: 0 0219 } 0220 PropertyChanges { 0221 target: closeButton 0222 opacity: 0 0223 } 0224 }, 0225 State { 0226 name: "partial" 0227 PropertyChanges { 0228 target: thumb 0229 x: (thumb.window.x - targetScreen.geometry.x - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.x : 0)) * (1 - thumb.partialActivationFactor) + cell.x * thumb.partialActivationFactor 0230 y: (thumb.window.y - targetScreen.geometry.y - (thumb.windowHeap.absolutePositioning ? windowHeap.layout.Kirigami.ScenePosition.y : 0)) * (1 - thumb.partialActivationFactor) + cell.y * thumb.partialActivationFactor 0231 width: thumb.window.width * (1 - thumb.partialActivationFactor) + cell.width * thumb.partialActivationFactor 0232 height: thumb.window.height * (1 - thumb.partialActivationFactor) + cell.height * thumb.partialActivationFactor 0233 opacity: thumb.initialHidden 0234 ? (thumb.activeHidden ? 0 : thumb.partialActivationFactor) 0235 : (thumb.activeHidden ? 1 - thumb.partialActivationFactor : 1) 0236 } 0237 PropertyChanges { 0238 target: thumbSource 0239 x: 0 0240 y: 0 0241 width: thumb.width 0242 height: thumb.height 0243 } 0244 PropertyChanges { 0245 target: icon 0246 opacity: thumb.partialActivationFactor 0247 } 0248 PropertyChanges { 0249 target: closeButton 0250 opacity: thumb.partialActivationFactor 0251 } 0252 }, 0253 State { 0254 name: "initial-hidden" 0255 extend: "initial" 0256 PropertyChanges { 0257 target: thumb 0258 opacity: 0 0259 } 0260 PropertyChanges { 0261 target: icon 0262 opacity: 0 0263 } 0264 PropertyChanges { 0265 target: closeButton 0266 opacity: 0 0267 } 0268 }, 0269 State { 0270 name: "active-hidden" 0271 extend: "initial-hidden" 0272 }, 0273 State { 0274 // this state is never directly used without a substate 0275 name: "active" 0276 PropertyChanges { 0277 target: thumb 0278 x: cell.x 0279 y: cell.y 0280 width: cell.width 0281 height: cell.height 0282 } 0283 PropertyChanges { 0284 target: icon 0285 opacity: 1 0286 } 0287 PropertyChanges { 0288 target: closeButton 0289 opacity: 1 0290 } 0291 }, 0292 State { 0293 name: "active-normal" 0294 extend: "active" 0295 PropertyChanges { 0296 target: thumbSource 0297 x: 0 0298 y: 0 0299 width: thumb.width 0300 height: thumb.height 0301 } 0302 }, 0303 State { 0304 name: "active-pressed" 0305 extend: "active" 0306 PropertyChanges { 0307 target: thumbSource 0308 width: thumb.width 0309 height: thumb.height 0310 } 0311 }, 0312 State { 0313 name: "active-drag" 0314 extend: "active" 0315 PropertyChanges { 0316 target: thumbSource 0317 x: -thumb.activeDragHandler.centroid.pressPosition.x * thumb.targetScale + 0318 thumb.activeDragHandler.centroid.position.x 0319 y: -thumb.activeDragHandler.centroid.pressPosition.y * thumb.targetScale + 0320 thumb.activeDragHandler.centroid.position.y 0321 width: thumb.width * thumb.targetScale 0322 height: thumb.height * thumb.targetScale 0323 } 0324 }, 0325 State { 0326 name: "active-reparenting" 0327 extend: "active" 0328 } 0329 ] 0330 0331 transitions: [ 0332 Transition { 0333 id: returning 0334 from: "active-drag, active-reparenting" 0335 to: "active-normal" 0336 enabled: thumb.windowHeap.animationEnabled 0337 NumberAnimation { 0338 duration: thumb.windowHeap.animationDuration 0339 properties: "x, y, width, height" 0340 easing.type: Easing.InOutCubic 0341 } 0342 } 0343 ] 0344 0345 HoverHandler { 0346 id: hoverHandler 0347 onHoveredChanged: if (hovered !== selected) { 0348 thumb.windowHeap.resetSelected(); 0349 } 0350 } 0351 0352 TapHandler { 0353 acceptedButtons: Qt.LeftButton 0354 onTapped: { 0355 KWinComponents.Workspace.activeWindow = thumb.window; 0356 thumb.windowHeap.activated(); 0357 } 0358 onPressedChanged: { 0359 if (pressed) { 0360 var saved = Qt.point(thumbSource.x, thumbSource.y); 0361 thumbSource.Drag.active = true; 0362 thumb.substate = "pressed"; 0363 thumbSource.x = saved.x; 0364 thumbSource.y = saved.y; 0365 } else if (!thumb.activeDragHandler.active) { 0366 thumbSource.Drag.active = false; 0367 thumb.substate = "normal"; 0368 } 0369 } 0370 } 0371 0372 component DragManager : DragHandler { 0373 target: null 0374 grabPermissions: PointerHandler.CanTakeOverFromAnything 0375 // This does not work when moving pointer fast and pressing along the way 0376 // See also QTBUG-105903, QTBUG-105904 0377 // enabled: thumb.state !== "active-normal" 0378 0379 onActiveChanged: { 0380 thumb.windowHeap.dragActive = active; 0381 if (active) { 0382 thumb.activeDragHandler = this; 0383 thumb.substate = "drag"; 0384 } else { 0385 thumbSource.saveDND(); 0386 0387 var action = thumbSource.Drag.drop(); 0388 if (action === Qt.MoveAction) { 0389 // This whole component is in the process of being destroyed due to drop onto 0390 // another virtual desktop (not another screen). 0391 if (typeof thumbSource !== "undefined") { 0392 // Except the case when it was dropped on the same desktop which it's already on, so let's return to normal state anyway. 0393 thumbSource.deleteDND(); 0394 thumb.substate = "normal"; 0395 } 0396 return; 0397 } 0398 0399 var globalPos = targetScreen.mapToGlobal(centroid.scenePosition); 0400 effect.checkItemDroppedOutOfScreen(globalPos, thumbSource); 0401 0402 if (typeof thumbSource !== "undefined") { 0403 // else, return to normal without reparenting 0404 thumbSource.deleteDND(); 0405 thumb.substate = "normal"; 0406 } 0407 } 0408 } 0409 } 0410 0411 DragManager { 0412 id: dragHandler 0413 acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus 0414 } 0415 0416 DragManager { 0417 id: touchDragHandler 0418 acceptedDevices: PointerDevice.TouchScreen 0419 readonly property double downGestureProgress: { 0420 if (!active) { 0421 return 0.0; 0422 } 0423 0424 const startDistance = thumb.windowHeap.Kirigami.ScenePosition.y + thumb.windowHeap.height - centroid.scenePressPosition.y; 0425 const localPosition = thumb.windowHeap.Kirigami.ScenePosition.y + thumb.windowHeap.height - centroid.scenePosition.y; 0426 return 1 - Math.min(localPosition/startDistance, 1); 0427 } 0428 0429 onActiveChanged: { 0430 if (!active) { 0431 if (downGestureProgress > 0.6) { 0432 thumb.downGestureTriggered(); 0433 } 0434 } 0435 } 0436 } 0437 0438 Loader { 0439 id: closeButton 0440 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft 0441 0442 anchors { 0443 right: thumbSource.right 0444 top: thumbSource.top 0445 margins: Kirigami.Units.smallSpacing 0446 } 0447 active: thumb.closeButtonVisible && (hoverHandler.hovered || Kirigami.Settings.tabletMode || Kirigami.Settings.hasTransientTouchInput) && thumb.window.closeable && !thumb.activeDragHandler.active 0448 0449 sourceComponent: PC3.Button { 0450 text: i18ndc("kwin", "@info:tooltip as in: 'close this window'", "Close window") 0451 icon.name: "window-close" 0452 display: PC3.AbstractButton.IconOnly 0453 0454 PC3.ToolTip.text: text 0455 PC3.ToolTip.visible: hovered && display === PC3.AbstractButton.IconOnly 0456 PC3.ToolTip.delay: Kirigami.Units.toolTipDelay 0457 Accessible.name: text 0458 0459 onClicked: thumb.window.closeWindow(); 0460 } 0461 } 0462 0463 Component.onDestruction: { 0464 if (selected) { 0465 windowHeap.resetSelected(); 0466 } 0467 } 0468 }