/* SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez SPDX-License-Identifier: GPL-2.0-or-later */ import QtQml 2.15 import QtQuick 2.8 import QtQuick.Controls 2.3 import QtQuick.Layouts 1.1 import QtGraphicalEffects 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.workspace.components 2.0 as PW import org.kde.kirigami 2.13 as Kirigami import org.kde.plasma.private.sessions 2.0 import "../components" PlasmaCore.ColorScope { id: lockScreenUi // If we're using software rendering, draw outlines instead of shadows // See https://bugs.kde.org/show_bug.cgi?id=398317 readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software property bool hadPrompt: false; property int currentPage: 0; colorGroup: PlasmaCore.Theme.ComplementaryColorGroup function setWrongPasswordScreen(msg) { root.clearPassword(); currentMessage.text = msg; currentMessageIcon.source = "dialog-error"; currentPage = 2; dismissButton.focus = true; } Connections { target: authenticator function onFailed() { if (root.notification) { root.notification += "\n" } setWrongPasswordScreen("The user name or password is incorrect."); lockScreenUi.hadPrompt = false; } function onSucceeded() { if (lockScreenUi.hadPrompt) { Qt.quit(); } else { currentPage = 4; noPasswordArea.forceActiveFocus(); } } function onInfoMessage(msg) { root.clearPassword(); currentMessage.text = msg; currentMessageIcon.source = "dialog-info"; currentPage = 2; dismissButton.focus = true; } function onErrorMessage(msg) { } function onPrompt(msg) { root.notification = msg; passwordArea.mainPasswordBox.forceActiveFocus(); lockScreenUi.hadPrompt = true; } function onPromptForSecret(msg) { passwordArea.mainPasswordBox.forceActiveFocus(); lockScreenUi.hadPrompt = true; } } SessionManagement { id: sessionManagement } Connections { target: sessionManagement function onAboutToSuspend() { root.clearPassword(); } } SessionsModel { id: sessionsModel showNewSessionEntry: false } PlasmaCore.DataSource { id: keystateSource engine: "keystate" connectedSources: "Caps Lock" } Loader { id: changeSessionComponent active: false source: "ChangeSession.qml" visible: false } WallpaperFader { anchors.fill: parent source: wallpaper } Loader { id: inputPanel state: "hidden" readonly property bool keyboardActive: item ? item.active : false anchors { left: parent.left right: parent.right bottom: lockScreenUi.bottom } function showHide() { state = state == "hidden" ? "visible" : "hidden"; } Component.onCompleted: { inputPanel.source = Qt.platform.pluginName.includes("wayland") ? "../components/VirtualKeyboard_wayland.qml" : "../components/VirtualKeyboard.qml" } onKeyboardActiveChanged: { if (keyboardActive) { inputPanel.z = 99; state = "visible"; } else { state = "hidden"; } } states: [ State { name: "visible" PropertyChanges { target: lockScreenRoot height: lockScreenUi.height - inputPanel.height; //y: 0 - inputPanel.height + passwordArea.height - (switchuserButton.height + switchuserButton.anchors.topMargin); } PropertyChanges { target: inputPanel y: lockScreenRoot.height - inputPanel.height } }, State { name: "hidden" PropertyChanges { target: lockScreenRoot height: lockScreenUi.height; } PropertyChanges { target: inputPanel y: lockScreenRoot.height - lockScreenRoot.height/4 } } ] transitions: [ Transition { from: "hidden" to: "visible" SequentialAnimation { ScriptAction { script: { inputPanel.item.activated = true; Qt.inputMethod.show(); } } ParallelAnimation { NumberAnimation { target: lockScreenRoot property: "height" duration: PlasmaCore.Units.longDuration easing.type: Easing.InOutQuad } NumberAnimation { target: inputPanel property: "y" duration: PlasmaCore.Units.longDuration easing.type: Easing.OutQuad } } } }, Transition { from: "visible" to: "hidden" SequentialAnimation { ParallelAnimation { NumberAnimation { target: lockScreenRoot property: "height" duration: PlasmaCore.Units.longDuration easing.type: Easing.InOutQuad } NumberAnimation { target: inputPanel property: "y" duration: PlasmaCore.Units.longDuration easing.type: Easing.InQuad } OpacityAnimator { target: inputPanel duration: PlasmaCore.Units.longDuration easing.type: Easing.InQuad } } ScriptAction { script: { inputPanel.item.activated = false; Qt.inputMethod.hide(); } } } } ] } MouseArea { id: lockScreenRoot property bool calledUnlock: false Component.onCompleted: { if (!calledUnlock) { calledUnlock = true authenticator.tryUnlock(); } } x: parent.x y: parent.y width: parent.width height: parent.height hoverEnabled: true drag.filterChildren: true Keys.onEscapePressed: { if (inputPanel.keyboardActive) { inputPanel.showHide(); } } Keys.onPressed: { event.accepted = false; } GenericButton { id: switchLayoutButton anchors { top: parent.top topMargin: 5 left: parent.left leftMargin: 7 } implicitWidth: 35 implicitHeight: 28 label.font.pointSize: 9 label.font.capitalization: Font.AllUppercase focusPolicy: Qt.TabFocus Accessible.description: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to change keyboard layout", "Switch layout") PW.KeyboardLayoutSwitcher { id: keyboardLayoutSwitcher anchors.fill: parent acceptedButtons: Qt.NoButton } text: keyboardLayoutSwitcher.layoutNames.shortName onClicked: keyboardLayoutSwitcher.keyboardLayout.switchToNextLayout() visible: keyboardLayoutSwitcher.hasMultipleKeyboardLayouts } ListModel { id: users Component.onCompleted: { users.append({ name: kscreenlocker_userName, realName: kscreenlocker_userName, icon: kscreenlocker_userImage, }) } } MainBlock { id: passwordArea anchors.centerIn: parent visible: currentPage == 0 focus: true onPasswordResult: { // Switch to the 'Welcome' screen currentPage = 1; authenticator.respond(password) } notificationMessage: { if (keystateSource.data["Caps Lock"]["Locked"]) { return i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Caps Lock is on"); } else { return ""; } } } NoPasswordUnlock { id: noPasswordArea anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: switchuserButton.top anchors.bottomMargin: 52 visible: currentPage == 4 onClicked: { Qt.quit(); } } GenericButton { id: switchuserButton visible: currentPage == 0 || currentPage == 4 label.font.pointSize: 11 implicitWidth: 108 implicitHeight: 28 focusPolicy: Qt.TabFocus Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Switch User") PlasmaComponents3.Label { font.pointSize: 11 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Switch User") anchors.fill: parent anchors.bottomMargin: PlasmaCore.Units.smallSpacing / 2 verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight layer.enabled: true layer.effect: DropShadow { //visible: !softwareRendering horizontalOffset: 0 verticalOffset: 1 radius: 6 samples: 14 spread: 0.0001 color: "#bf000000" } } onClicked: { sessionsModel.startNewSession(true /* lock the screen too */) lockScreenRoot.state = '' passwordArea.mainPasswordBox.forceActiveFocus(); } anchors { top: passwordArea.bottom topMargin: (currentPage == 4 ? 36 : 40) / (inputPanel.keyboardActive ? 4 : 1) // for some reason, Microsoft offset Windows 7's Switch User button a bit when in no password lock horizontalCenter: parent.horizontalCenter } } RowLayout { visible: currentPage == 0 || currentPage == 4 id: footer anchors { bottom: parent.bottom left: parent.left right: parent.right margins: 34 } EoAButton { } OSKButton { onClicked: { // Otherwise the password field loses focus and virtual keyboard // keystrokes get eaten passwordArea.mainPasswordBox.forceActiveFocus(); inputPanel.showHide() } visible: inputPanel.status == Loader.Ready } Item { Layout.fillWidth: true } } Item { id: welcomePage visible: currentPage == 1 anchors.fill: parent Status { id: statusText anchors.centerIn: parent anchors.verticalCenterOffset: -36 statusText: i18nd("okular", "Welcome") speen: welcomePage.visible } } ColumnLayout { id: messagePage visible: currentPage == 2 anchors { bottom: switchuserButton.bottom horizontalCenter: parent.horizontalCenter } spacing: 0 RowLayout { spacing: 10 Kirigami.Icon { id: currentMessageIcon implicitHeight: 32 implicitWidth: 32 } Label { id: currentMessage Layout.alignment: Qt.AlignHCenter font.pointSize: 9 width: implicitWidth color: "white" horizontalAlignment: Text.AlignCenter layer.enabled: true layer.effect: DropShadow { //visible: !softwareRendering horizontalOffset: 0 verticalOffset: 1 radius: 6 samples: 14 spread: 0.0001 color: "#bf000000" } } } Item { height: 40 } GenericButton { id: dismissButton Layout.alignment: Qt.AlignHCenter font.pointSize: 11 implicitWidth: 93 implicitHeight: 28 focusPolicy: Qt.TabFocus Accessible.name: "OK" text: "OK" onClicked: { authenticator.tryUnlock(); currentPage = 0; passwordArea.mainPasswordBox.forceActiveFocus(); } } } RowLayout { anchors { bottom: parent.bottom left: parent.left right: parent.right } height: 96 Rectangle { Layout.fillWidth: true } Image { id: watermark source: "../images/watermark.png" opacity: !inputPanel.keyboardActive } Rectangle { Layout.fillWidth: true } } Loader { active: true source: "LockOsd.qml" anchors { horizontalCenter: parent.horizontalCenter top: parent.top topMargin: PlasmaCore.Units.largeSpacing } } } }