Warning, /plasma/plasma-workspace/lookandfeel/sddm-theme/Main.qml is written in an unsupported language. File is not indexed.
0001 /*
0002 SPDX-FileCopyrightText: 2016 David Edmundson <davidedmundson@kde.org>
0003
0004 SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006
0007 import QtQuick 2.15
0008 import QtQuick.Layouts 1.15
0009 import QtQuick.Controls 2.15 as QQC2
0010 import Qt5Compat.GraphicalEffects
0011
0012 import org.kde.plasma.components 3.0 as PlasmaComponents3
0013 import org.kde.plasma.private.keyboardindicator as KeyboardIndicator
0014 import org.kde.kirigami 2.20 as Kirigami
0015
0016 import org.kde.breeze.components
0017
0018 // TODO: Once SDDM 0.19 is released and we are setting the font size using the
0019 // SDDM KCM's syncing feature, remove the `config.fontSize` overrides here and
0020 // the fontSize properties in various components, because the theme's default
0021 // font size will be correctly propagated to the login screen
0022
0023 Item {
0024 id: root
0025
0026 // If we're using software rendering, draw outlines instead of shadows
0027 // See https://bugs.kde.org/show_bug.cgi?id=398317
0028 readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software
0029
0030 Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
0031 Kirigami.Theme.inherit: false
0032
0033 width: 1600
0034 height: 900
0035
0036 property string notificationMessage
0037
0038 LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
0039 LayoutMirroring.childrenInherit: true
0040
0041 KeyboardIndicator.KeyState {
0042 id: capsLockState
0043 key: Qt.Key_CapsLock
0044 }
0045
0046 Item {
0047 id: wallpaper
0048 anchors.fill: parent
0049 Repeater {
0050 model: screenModel
0051
0052 Background {
0053 x: geometry.x; y: geometry.y; width: geometry.width; height: geometry.height
0054 sceneBackgroundType: config.type
0055 sceneBackgroundColor: config.color
0056 sceneBackgroundImage: config.background
0057 }
0058 }
0059 }
0060
0061 RejectPasswordAnimation {
0062 id: rejectPasswordAnimation
0063 target: mainStack
0064 }
0065
0066 MouseArea {
0067 id: loginScreenRoot
0068 anchors.fill: parent
0069
0070 property bool uiVisible: true
0071 property bool blockUI: mainStack.depth > 1 || userListComponent.mainPasswordBox.text.length > 0 || inputPanel.keyboardActive || config.type !== "image"
0072
0073 hoverEnabled: true
0074 drag.filterChildren: true
0075 onPressed: uiVisible = true;
0076 onPositionChanged: uiVisible = true;
0077 onUiVisibleChanged: {
0078 if (blockUI) {
0079 fadeoutTimer.running = false;
0080 } else if (uiVisible) {
0081 fadeoutTimer.restart();
0082 }
0083 }
0084 onBlockUIChanged: {
0085 if (blockUI) {
0086 fadeoutTimer.running = false;
0087 uiVisible = true;
0088 } else {
0089 fadeoutTimer.restart();
0090 }
0091 }
0092
0093 Keys.onPressed: event => {
0094 uiVisible = true;
0095 event.accepted = false;
0096 }
0097
0098 //takes one full minute for the ui to disappear
0099 Timer {
0100 id: fadeoutTimer
0101 running: true
0102 interval: 60000
0103 onTriggered: {
0104 if (!loginScreenRoot.blockUI) {
0105 userListComponent.mainPasswordBox.showPassword = false;
0106 loginScreenRoot.uiVisible = false;
0107 }
0108 }
0109 }
0110 WallpaperFader {
0111 visible: config.type === "image"
0112 anchors.fill: parent
0113 state: loginScreenRoot.uiVisible ? "on" : "off"
0114 source: wallpaper
0115 mainStack: mainStack
0116 footer: footer
0117 clock: clock
0118 }
0119
0120 DropShadow {
0121 id: clockShadow
0122 anchors.fill: clock
0123 source: clock
0124 visible: !softwareRendering
0125 radius: 6
0126 samples: 14
0127 spread: 0.3
0128 color : "black" // shadows should always be black
0129 Behavior on opacity {
0130 OpacityAnimator {
0131 duration: Kirigami.Units.veryLongDuration * 2
0132 easing.type: Easing.InOutQuad
0133 }
0134 }
0135 }
0136
0137 Clock {
0138 id: clock
0139 property Item shadow: clockShadow
0140 visible: y > 0
0141 anchors.horizontalCenter: parent.horizontalCenter
0142 y: (userListComponent.userList.y + mainStack.y)/2 - height/2
0143 Layout.alignment: Qt.AlignBaseline
0144 }
0145
0146 QQC2.StackView {
0147 id: mainStack
0148 anchors {
0149 left: parent.left
0150 right: parent.right
0151 }
0152 height: root.height + Kirigami.Units.gridUnit * 3
0153
0154 // If true (depends on the style and environment variables), hover events are always accepted
0155 // and propagation stopped. This means the parent MouseArea won't get them and the UI won't be shown.
0156 // Disable capturing those events while the UI is hidden to avoid that, while still passing events otherwise.
0157 // One issue is that while the UI is visible, mouse activity won't keep resetting the timer, but when it
0158 // finally expires, the next event should immediately set uiVisible = true again.
0159 hoverEnabled: loginScreenRoot.uiVisible ? undefined : false
0160
0161 focus: true //StackView is an implicit focus scope, so we need to give this focus so the item inside will have it
0162
0163 Timer {
0164 //SDDM has a bug in 0.13 where even though we set the focus on the right item within the window, the window doesn't have focus
0165 //it is fixed in 6d5b36b28907b16280ff78995fef764bb0c573db which will be 0.14
0166 //we need to call "window->activate()" *After* it's been shown. We can't control that in QML so we use a shoddy timer
0167 //it's been this way for all Plasma 5.x without a huge problem
0168 running: true
0169 repeat: false
0170 interval: 200
0171 onTriggered: mainStack.forceActiveFocus()
0172 }
0173
0174 initialItem: Login {
0175 id: userListComponent
0176 userListModel: userModel
0177 loginScreenUiVisible: loginScreenRoot.uiVisible
0178 userListCurrentIndex: userModel.lastIndex >= 0 ? userModel.lastIndex : 0
0179 lastUserName: userModel.lastUser
0180 showUserList: {
0181 if (!userListModel.hasOwnProperty("count")
0182 || !userListModel.hasOwnProperty("disableAvatarsThreshold")) {
0183 return false
0184 }
0185
0186 if (userListModel.count === 0 ) {
0187 return false
0188 }
0189
0190 if (userListModel.hasOwnProperty("containsAllUsers") && !userListModel.containsAllUsers) {
0191 return false
0192 }
0193
0194 return userListModel.count <= userListModel.disableAvatarsThreshold
0195 }
0196
0197 notificationMessage: {
0198 const parts = [];
0199 if (capsLockState.locked) {
0200 parts.push(i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Caps Lock is on"));
0201 }
0202 if (root.notificationMessage) {
0203 parts.push(root.notificationMessage);
0204 }
0205 return parts.join(" • ");
0206 }
0207
0208 actionItemsVisible: !inputPanel.keyboardActive
0209 actionItems: [
0210 ActionButton {
0211 iconSource: "system-suspend"
0212 text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Suspend to RAM", "Sleep")
0213 fontSize: parseInt(config.fontSize) + 1
0214 onClicked: sddm.suspend()
0215 enabled: sddm.canSuspend
0216 },
0217 ActionButton {
0218 iconSource: "system-reboot"
0219 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Restart")
0220 fontSize: parseInt(config.fontSize) + 1
0221 onClicked: sddm.reboot()
0222 enabled: sddm.canReboot
0223 },
0224 ActionButton {
0225 iconSource: "system-shutdown"
0226 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down")
0227 fontSize: parseInt(config.fontSize) + 1
0228 onClicked: sddm.powerOff()
0229 enabled: sddm.canPowerOff
0230 },
0231 ActionButton {
0232 iconSource: "system-user-prompt"
0233 text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "For switching to a username and password prompt", "Other…")
0234 fontSize: parseInt(config.fontSize) + 1
0235 onClicked: mainStack.push(userPromptComponent)
0236 enabled: true
0237 visible: !userListComponent.showUsernamePrompt
0238 }]
0239
0240 onLoginRequest: {
0241 root.notificationMessage = ""
0242 sddm.login(username, password, sessionButton.currentIndex)
0243 }
0244 }
0245
0246 Behavior on opacity {
0247 OpacityAnimator {
0248 duration: Kirigami.Units.longDuration
0249 }
0250 }
0251
0252 readonly property real zoomFactor: 1.5
0253
0254 popEnter: Transition {
0255 ScaleAnimator {
0256 from: mainStack.zoomFactor
0257 to: 1
0258 duration: Kirigami.Units.veryLongDuration
0259 easing.type: Easing.OutCubic
0260 }
0261 OpacityAnimator {
0262 from: 0
0263 to: 1
0264 duration: Kirigami.Units.veryLongDuration
0265 easing.type: Easing.OutCubic
0266 }
0267 }
0268
0269 popExit: Transition {
0270 ScaleAnimator {
0271 from: 1
0272 to: 1 / mainStack.zoomFactor
0273 duration: Kirigami.Units.veryLongDuration
0274 easing.type: Easing.OutCubic
0275 }
0276 OpacityAnimator {
0277 from: 1
0278 to: 0
0279 duration: Kirigami.Units.veryLongDuration
0280 easing.type: Easing.OutCubic
0281 }
0282 }
0283
0284 pushEnter: Transition {
0285 ScaleAnimator {
0286 from: 1 / mainStack.zoomFactor
0287 to: 1
0288 duration: Kirigami.Units.veryLongDuration
0289 easing.type: Easing.OutCubic
0290 }
0291 OpacityAnimator {
0292 from: 0
0293 to: 1
0294 duration: Kirigami.Units.veryLongDuration
0295 easing.type: Easing.OutCubic
0296 }
0297 }
0298
0299 pushExit: Transition {
0300 ScaleAnimator {
0301 from: 1
0302 to: mainStack.zoomFactor
0303 duration: Kirigami.Units.veryLongDuration
0304 easing.type: Easing.OutCubic
0305 }
0306 OpacityAnimator {
0307 from: 1
0308 to: 0
0309 duration: Kirigami.Units.veryLongDuration
0310 easing.type: Easing.OutCubic
0311 }
0312 }
0313 }
0314
0315 VirtualKeyboardLoader {
0316 id: inputPanel
0317
0318 z: 1
0319
0320 screenRoot: root
0321 mainStack: mainStack
0322 mainBlock: userListComponent
0323 passwordField: userListComponent.mainPasswordBox
0324 }
0325
0326 Component {
0327 id: userPromptComponent
0328 Login {
0329 showUsernamePrompt: true
0330 notificationMessage: root.notificationMessage
0331 loginScreenUiVisible: loginScreenRoot.uiVisible
0332 fontSize: parseInt(config.fontSize) + 2
0333
0334 // using a model rather than a QObject list to avoid QTBUG-75900
0335 userListModel: ListModel {
0336 ListElement {
0337 name: ""
0338 icon: ""
0339 }
0340 Component.onCompleted: {
0341 // as we can't bind inside ListElement
0342 setProperty(0, "name", i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Type in Username and Password"));
0343 setProperty(0, "icon", Qt.resolvedUrl("faces/.face.icon"))
0344 }
0345 }
0346
0347 onLoginRequest: {
0348 root.notificationMessage = ""
0349 sddm.login(username, password, sessionButton.currentIndex)
0350 }
0351
0352 actionItemsVisible: !inputPanel.keyboardActive
0353 actionItems: [
0354 ActionButton {
0355 iconSource: "system-suspend"
0356 text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Suspend to RAM", "Sleep")
0357 fontSize: parseInt(config.fontSize) + 1
0358 onClicked: sddm.suspend()
0359 enabled: sddm.canSuspend
0360 },
0361 ActionButton {
0362 iconSource: "system-reboot"
0363 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Restart")
0364 fontSize: parseInt(config.fontSize) + 1
0365 onClicked: sddm.reboot()
0366 enabled: sddm.canReboot
0367 },
0368 ActionButton {
0369 iconSource: "system-shutdown"
0370 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down")
0371 fontSize: parseInt(config.fontSize) + 1
0372 onClicked: sddm.powerOff()
0373 enabled: sddm.canPowerOff
0374 },
0375 ActionButton {
0376 iconSource: "system-user-list"
0377 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "List Users")
0378 fontSize: parseInt(config.fontSize) + 1
0379 onClicked: mainStack.pop()
0380 }
0381 ]
0382 }
0383 }
0384
0385 DropShadow {
0386 id: logoShadow
0387 anchors.fill: logo
0388 source: logo
0389 visible: !softwareRendering && config.showlogo === "shown"
0390 horizontalOffset: 1
0391 verticalOffset: 1
0392 radius: 6
0393 samples: 14
0394 spread: 0.3
0395 color : "black" // shadows should always be black
0396 opacity: loginScreenRoot.uiVisible ? 0 : 1
0397 Behavior on opacity {
0398 //OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)"
0399 NumberAnimation {
0400 duration: Kirigami.Units.longDuration
0401 easing.type: Easing.InOutQuad
0402 }
0403 }
0404 }
0405
0406 Image {
0407 id: logo
0408 visible: config.showlogo === "shown"
0409 source: config.logo
0410 anchors.horizontalCenter: parent.horizontalCenter
0411 anchors.bottom: footer.top
0412 anchors.bottomMargin: Kirigami.Units.largeSpacing
0413 asynchronous: true
0414 sourceSize.height: height
0415 opacity: loginScreenRoot.uiVisible ? 0 : 1
0416 fillMode: Image.PreserveAspectFit
0417 height: Math.round(Kirigami.Units.gridUnit * 3.5)
0418 Behavior on opacity {
0419 // OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)"
0420 NumberAnimation {
0421 duration: Kirigami.Units.longDuration
0422 easing.type: Easing.InOutQuad
0423 }
0424 }
0425 }
0426
0427 // Note: Containment masks stretch clickable area of their buttons to
0428 // the screen edges, essentially making them adhere to Fitts's law.
0429 // Due to virtual keyboard button having an icon, buttons may have
0430 // different heights, so fillHeight is required.
0431 //
0432 // Note for contributors: Keep this in sync with LockScreenUi.qml footer.
0433 RowLayout {
0434 id: footer
0435 anchors {
0436 bottom: parent.bottom
0437 left: parent.left
0438 right: parent.right
0439 margins: Kirigami.Units.smallSpacing
0440 }
0441 spacing: Kirigami.Units.smallSpacing
0442
0443 Behavior on opacity {
0444 OpacityAnimator {
0445 duration: Kirigami.Units.longDuration
0446 }
0447 }
0448
0449 PlasmaComponents3.ToolButton {
0450 id: virtualKeyboardButton
0451
0452 text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard")
0453 font.pointSize: config.fontSize
0454 icon.name: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off"
0455 onClicked: {
0456 // Otherwise the password field loses focus and virtual keyboard
0457 // keystrokes get eaten
0458 userListComponent.mainPasswordBox.forceActiveFocus();
0459 inputPanel.showHide()
0460 }
0461 visible: inputPanel.status === Loader.Ready
0462
0463 Layout.fillHeight: true
0464 containmentMask: Item {
0465 parent: virtualKeyboardButton
0466 anchors.fill: parent
0467 anchors.leftMargin: -footer.anchors.margins
0468 anchors.bottomMargin: -footer.anchors.margins
0469 }
0470 }
0471
0472 KeyboardButton {
0473 id: keyboardButton
0474
0475 font.pointSize: config.fontSize
0476
0477 onKeyboardLayoutChanged: {
0478 // Otherwise the password field loses focus and virtual keyboard
0479 // keystrokes get eaten
0480 userListComponent.mainPasswordBox.forceActiveFocus();
0481 }
0482
0483 Layout.fillHeight: true
0484 containmentMask: Item {
0485 parent: keyboardButton
0486 anchors.fill: parent
0487 anchors.leftMargin: virtualKeyboardButton.visible ? 0 : -footer.anchors.margins
0488 anchors.bottomMargin: -footer.anchors.margins
0489 }
0490 }
0491
0492 SessionButton {
0493 id: sessionButton
0494
0495 font.pointSize: config.fontSize
0496
0497 onSessionChanged: {
0498 // Otherwise the password field loses focus and virtual keyboard
0499 // keystrokes get eaten
0500 userListComponent.mainPasswordBox.forceActiveFocus();
0501 }
0502
0503 Layout.fillHeight: true
0504 containmentMask: Item {
0505 parent: sessionButton
0506 anchors.fill: parent
0507 anchors.leftMargin: virtualKeyboardButton.visible || keyboardButton.visible
0508 ? 0 : -footer.anchors.margins
0509 anchors.bottomMargin: -footer.anchors.margins
0510 }
0511 }
0512
0513 Item {
0514 Layout.fillWidth: true
0515 }
0516
0517 Battery {
0518 fontSize: config.fontSize
0519 }
0520 }
0521 }
0522
0523 Connections {
0524 target: sddm
0525 function onLoginFailed() {
0526 notificationMessage = i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Login Failed")
0527 footer.enabled = true
0528 mainStack.enabled = true
0529 userListComponent.userList.opacity = 1
0530 rejectPasswordAnimation.start()
0531 }
0532 function onLoginSucceeded() {
0533 //note SDDM will kill the greeter at some random point after this
0534 //there is no certainty any transition will finish, it depends on the time it
0535 //takes to complete the init
0536 mainStack.opacity = 0
0537 footer.opacity = 0
0538 }
0539 }
0540
0541 onNotificationMessageChanged: {
0542 if (notificationMessage) {
0543 notificationResetTimer.start();
0544 }
0545 }
0546
0547 Timer {
0548 id: notificationResetTimer
0549 interval: 3000
0550 onTriggered: notificationMessage = ""
0551 }
0552 }