File indexing completed on 2024-11-10 04:57:06
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2018, 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 "use strict"; 0011 0012 const blacklist = [ 0013 // The logout screen has to be animated only by the logout effect. 0014 "ksmserver ksmserver", 0015 "ksmserver-logout-greeter ksmserver-logout-greeter", 0016 0017 // KDE Plasma splash screen has to be animated only by the login effect. 0018 "ksplashqml ksplashqml", 0019 0020 // Spectacle needs to be blacklisted in order to stay out of its own screenshots. 0021 "spectacle spectacle", // x11 0022 "spectacle org.kde.spectacle", // wayland 0023 ]; 0024 0025 class ScaleEffect { 0026 constructor() { 0027 effect.configChanged.connect(this.loadConfig.bind(this)); 0028 effect.animationEnded.connect(this.cleanupForcedRoles.bind(this)); 0029 effects.windowAdded.connect(this.slotWindowAdded.bind(this)); 0030 effects.windowClosed.connect(this.slotWindowClosed.bind(this)); 0031 effects.windowDataChanged.connect(this.slotWindowDataChanged.bind(this)); 0032 0033 this.loadConfig(); 0034 } 0035 0036 loadConfig() { 0037 const defaultDuration = 200; 0038 const duration = effect.readConfig("Duration", defaultDuration) || defaultDuration; 0039 this.duration = animationTime(duration); 0040 this.inScale = effect.readConfig("InScale", 0.8); 0041 this.outScale = effect.readConfig("OutScale", 0.8); 0042 } 0043 0044 static isScaleWindow(window) { 0045 // We don't want to animate most of plasmashell's windows, yet, some 0046 // of them we want to, for example, Task Manager Settings window. 0047 // The problem is that all those window share single window class. 0048 // So, the only way to decide whether a window should be animated is 0049 // to use a heuristic: if a window has decoration, then it's most 0050 // likely a dialog or a settings window so we have to animate it. 0051 if (window.windowClass == "plasmashell plasmashell" 0052 || window.windowClass == "plasmashell org.kde.plasmashell") { 0053 return window.hasDecoration; 0054 } 0055 0056 if (blacklist.indexOf(window.windowClass) != -1) { 0057 return false; 0058 } 0059 0060 if (window.hasDecoration) { 0061 return true; 0062 } 0063 0064 // Don't animate combobox popups, tooltips, popup menus, etc. 0065 if (window.popupWindow) { 0066 return false; 0067 } 0068 0069 // Dont't animate the outline and the screenlocker as it looks bad. 0070 if (window.lockScreen || window.outline) { 0071 return false; 0072 } 0073 0074 // Override-redirect windows are usually used for user interface 0075 // concepts that are not expected to be animated by this effect. 0076 if (!window.managed) { 0077 return false; 0078 } 0079 0080 return window.normalWindow || window.dialog; 0081 } 0082 0083 setupForcedRoles(window) { 0084 window.setData(Effect.WindowForceBackgroundContrastRole, true); 0085 window.setData(Effect.WindowForceBlurRole, true); 0086 } 0087 0088 cleanupForcedRoles(window) { 0089 window.setData(Effect.WindowForceBackgroundContrastRole, null); 0090 window.setData(Effect.WindowForceBlurRole, null); 0091 } 0092 0093 slotWindowAdded(window) { 0094 if (effects.hasActiveFullScreenEffect) { 0095 return; 0096 } 0097 if (!ScaleEffect.isScaleWindow(window)) { 0098 return; 0099 } 0100 if (!window.visible) { 0101 return; 0102 } 0103 if (effect.isGrabbed(window, Effect.WindowAddedGrabRole)) { 0104 return; 0105 } 0106 this.setupForcedRoles(window); 0107 window.scaleInAnimation = animate({ 0108 window: window, 0109 curve: QEasingCurve.OutCubic, 0110 duration: this.duration, 0111 animations: [ 0112 { 0113 type: Effect.Scale, 0114 from: this.inScale 0115 }, 0116 { 0117 type: Effect.Opacity, 0118 from: 0 0119 } 0120 ] 0121 }); 0122 } 0123 0124 slotWindowClosed(window) { 0125 if (effects.hasActiveFullScreenEffect) { 0126 return; 0127 } 0128 if (!ScaleEffect.isScaleWindow(window)) { 0129 return; 0130 } 0131 if (!window.visible || window.skipsCloseAnimation) { 0132 return; 0133 } 0134 if (effect.isGrabbed(window, Effect.WindowClosedGrabRole)) { 0135 return; 0136 } 0137 if (window.scaleInAnimation) { 0138 cancel(window.scaleInAnimation); 0139 delete window.scaleInAnimation; 0140 } 0141 this.setupForcedRoles(window); 0142 window.scaleOutAnimation = animate({ 0143 window: window, 0144 curve: QEasingCurve.InCubic, 0145 duration: this.duration, 0146 animations: [ 0147 { 0148 type: Effect.Scale, 0149 to: this.outScale 0150 }, 0151 { 0152 type: Effect.Opacity, 0153 to: 0 0154 } 0155 ] 0156 }); 0157 } 0158 0159 slotWindowDataChanged(window, role) { 0160 if (role == Effect.WindowAddedGrabRole) { 0161 if (window.scaleInAnimation && effect.isGrabbed(window, role)) { 0162 cancel(window.scaleInAnimation); 0163 delete window.scaleInAnimation; 0164 this.cleanupForcedRoles(window); 0165 } 0166 } else if (role == Effect.WindowClosedGrabRole) { 0167 if (window.scaleOutAnimation && effect.isGrabbed(window, role)) { 0168 cancel(window.scaleOutAnimation); 0169 delete window.scaleOutAnimation; 0170 this.cleanupForcedRoles(window); 0171 } 0172 } 0173 } 0174 } 0175 0176 new ScaleEffect();