import QtQuick import SddmComponents import QtQuick.Layouts import Qt5Compat.GraphicalEffects import QtQuick.Controls as QQC2 import "SMOD" as SMOD import org.kde.plasma.components as PlasmaComponents3 import org.kde.plasma.extras as PlasmaExtras import org.kde.kirigami as Kirigami import org.kde.plasma.plasma5support as Plasma5Support import org.kde.kitemmodels as KItemModels import QtMultimedia Item { id: root LayoutMirroring.enabled : Qt.locale().textDirection == Qt.RightToLeft LayoutMirroring.childrenInherit : true property bool m_forceUserSelect: config.boolValue("forceUserSelect") property bool m_biggerUserFrame: config.boolValue("biggerUserFrame") property bool m_biggerMultiUserFrame: config.boolValue("biggerMultiUserFrame") enum LoginPage { Startup, SelectUser, Login, LoginFailed } // copied from sddm/src/greeter/UserModel.h because // it doesn't seem accessible via e.g. SDDM.UserModel.NameRole enum UserRoles { NameRole = 257, RealNameRole, HomeDirRole, IconRole, NeedsPasswordRole } Connections { target: sddm function onLoginFailed() { password.text = "" pages.currentIndex = Main.LoginPage.LoginFailed } } Keys.onEscapePressed: { if (pages.currentIndex === Main.LoginPage.Login && switchuser.enabled) { password.text = "" pages.currentIndex = Main.LoginPage.SelectUser } else if (pages.currentIndex === Main.LoginPage.LoginFailed) { pages.currentIndex = Main.LoginPage.Login } } Rectangle { color: "#1D5F7A" anchors.fill: parent } Background { id: background anchors.fill: parent fillMode: Image.Stretch source: Qt.resolvedUrl("background") } Timer { id: startupSoundDelay interval: config.boolValue("enableStartup") ? 250 : 20 running: startupSound.playSound onTriggered: { startupSound.play() } } MediaPlayer { id: startupSound property bool playSound: !executable.fileExists && config.boolValue("playSound") audioOutput: AudioOutput { volume: 1.0 } source: "Assets/session-start.wav" } Component { id: userDelegate Column { id: delegateColumn width: listView.cellWidth height: listView.cellHeight Item { id: avatarparent width: m_biggerMultiUserFrame ? 100 : 80 height: width anchors.centerIn: parent Item { width: m_biggerMultiUserFrame ? 60 : 48 height: width anchors.centerIn: parent Rectangle { id: maskmini anchors.fill: parent anchors.centerIn: parent radius: 2 visible: false } LinearGradient { id: gradient anchors.fill: parent anchors.centerIn: parent z: -1 start: Qt.point(0,0) end: Qt.point(gradient.width, gradient.height) gradient: Gradient { GradientStop { position: 0.0; color: "#eeecee" } GradientStop { position: 1.0; color: "#a39ea3" } } } Image { id: avatarmini property string m_fallbackPicture: "Assets/user.png" onStatusChanged: { if (avatarmini.status == Image.Error) { avatarmini.source = avatarmini.m_fallbackPicture; } } source: model.icon fillMode: Image.PreserveAspectCrop anchors.fill: parent anchors.centerIn: parent layer.enabled: true layer.effect: OpacityMask { maskSource: maskmini } } } Image { id: avatarminiframe property bool m_hovered: false source: { if (m_biggerMultiUserFrame) { if (m_hovered && delegateColumn.focus) return "Assets/12235.png" if (m_hovered && !delegateColumn.focus) return "Assets/12233.png" if (!m_hovered && delegateColumn.focus) return "Assets/12234.png" if (!m_hovered && !delegateColumn.focus) return "Assets/12237.png" } else { if (m_hovered && delegateColumn.focus) return "Assets/12220.png" if (m_hovered && !delegateColumn.focus) return "Assets/12218.png" if (!m_hovered && delegateColumn.focus) return "Assets/12219.png" if (!m_hovered && !delegateColumn.focus) return "Assets/12222.png" } } anchors.fill: parent anchors.centerIn: parent } } Text { text: (model.realName === "") ? model.name : model.realName color: "white" font.pixelSize: 12 //font.family: mainfont.name renderType: Text.NativeRendering font.hintingPreference: Font.PreferFullHinting font.kerning: false anchors.top: avatarparent.bottom //anchors.topMargin: -3 anchors.horizontalCenter: avatarparent.horizontalCenter layer.enabled: true layer.effect: DropShadow { verticalOffset: 1 color: "#000" radius: 7 samples: 20 } } MouseArea { anchors.fill: delegateColumn hoverEnabled: true onEntered: { avatarminiframe.m_hovered = true } onExited: { avatarminiframe.m_hovered = false } } Keys.onReturnPressed: { if (focus) { let username = model.name if (username != null) { let realname = model.realName let pic = model.icon let needspassword = model.needsPassword if (needspassword) { userNameLabel.text = realname avatar.source = pic listView.currentIndex = index pages.currentIndex = Main.LoginPage.Login } else { sddm.login(username, password.text, session.index) } } } } } } Loader { id: inputPanel state: "hidden" property bool active: false readonly property bool keyboardActive: item ? item.active : false anchors { left: parent.left right: parent.right bottom: background.bottom leftMargin: Kirigami.Units.gridUnit*12 rightMargin: Kirigami.Units.gridUnit*12 } function showHide() { active = !active; inputPanel.item.activated = Qt.binding(() => { return active }); } Component.onCompleted: { inputPanel.source = Qt.platform.pluginName.includes("wayland") ? "SMOD/VirtualKeyboard_wayland.qml" : "SMOD/VirtualKeyboard.qml" if(inputPanel.status === Loader.Ready) { var menuitem = session.createMenuSeparator(); session.addItem(menuitem); menuitem = session.createMenuItem(); menuitem.text = i18nd("aerothemeplasma-sddm-theme", "On-Screen Keyboard") menuitem.checkable = false; menuitem.icon.source = Qt.resolvedUrl("Assets/keyboard.png"); menuitem.triggered.connect(() => { password.forceActiveFocus(); inputPanel.showHide(); }); session.addAction(menuitem); } } onKeyboardActiveChanged: { if (keyboardActive) { inputPanel.z = 99; Qt.inputMethod.show(); active = true; } else { //inputPanel.item.activated = false; Qt.inputMethod.hide(); active = false; } } } StackLayout { id: pages anchors.fill: parent anchors.bottomMargin: inputPanel.active ? inputPanel.height : 0 onCurrentIndexChanged: { if (currentIndex == Main.LoginPage.SelectUser) { listView.forceActiveFocus() } else if (currentIndex == Main.LoginPage.Login) { password.forceActiveFocus() } else if (currentIndex == Main.LoginPage.LoginFailed) { dismissButton.forceActiveFocus() } } Plasma5Support.DataSource { id: executable engine: "executable" connectedSources: [] property bool read: false property bool startupEnabled: !fileExists && config.boolValue("enableStartup"); property bool fileExists: false onNewData: (sourceName, data) => { var stdout = data["stdout"] exited(stdout) disconnectSource(sourceName) // cmd finished } function exec(cmd, r) { executable.read = r; if (cmd) { connectSource(cmd) } } signal exited(string stdout) } Connections { target: executable function onExited(stdout) { if(executable.read) { if(stdout.trim() !== "") { // If the file exists, do not play Vista boot animation executable.fileExists = true; } else { executable.exec("touch /tmp/sddm.startup", false); // Create it to prevent multiple boot animations from happening if(startupSound.playSound) { startupSoundDelay.start() } if(executable.startupEnabled) seqanimation.start(); } } } } // for testing failed login currentIndex: { return executable.startupEnabled ? Main.LoginPage.Startup : Main.LoginPage.SelectUser } function startSingleUserMode() { let singleusermode = userModel.count < 2 && !m_forceUserSelect if (singleusermode) { let index = 0; let username = userModel.data(userModel.index(index, 0), Main.UserRoles.NameRole) if (username != null) { let userDisplayName = userModel.data(userModel.index(index, 0), Main.UserRoles.RealNameRole) let userPicture = userModel.data(userModel.index(index, 0), Main.UserRoles.IconRole) userNameLabel.text = userDisplayName avatar.source = userPicture pages.currentIndex = Main.LoginPage.Login return true; } } pages.currentIndex = Main.LoginPage.SelectUser; return false; } Component.onCompleted: { executable.exec("ls /tmp/sddm.startup", true); // Check if sddm.startup exists startSingleUserMode(); } Item { id: startupPage } Item { id: userlistpage anchors.fill: parent GridView { id: listView anchors.centerIn: parent anchors.verticalCenterOffset: { if (count < 5) { return 72 } else { return 0 } } width: { if (count < 5) { return cellWidth * count } else { return cellWidth * 5 } } height: { if (count > 5) { return 200 * 2 } else { return 200 } } clip: true interactive: true keyNavigationEnabled: true keyNavigationWraps: false focus: true boundsBehavior: Flickable.StopAtBounds QQC2.ScrollBar.vertical: QQC2.ScrollBar {} cellWidth: 200 cellHeight: 200 model: userModel delegate: userDelegate currentIndex: userModel.lastIndex KeyNavigation.backtab: rebootButton KeyNavigation.tab: accessbutton MouseArea { anchors.fill: parent onClicked: (mouse) => { let posInGridView = Qt.point(mouse.x, mouse.y) let posInContentItem = mapToItem(listView.contentItem, posInGridView) let index = listView.indexAt(posInContentItem.x, posInContentItem.y) let username = userModel.data(userModel.index(index, 0), Main.UserRoles.NameRole) if (username != null) { let realname = userModel.data(userModel.index(index, 0), Main.UserRoles.RealNameRole) let pic = userModel.data(userModel.index(index, 0), Main.UserRoles.IconRole) let needspassword = userModel.data(userModel.index(index, 0), Main.UserRoles.NeedsPasswordRole) if (needspassword) { userNameLabel.text = realname == "" ? username : realname; avatar.source = pic listView.currentIndex = index pages.currentIndex = Main.LoginPage.Login } else { sddm.login(username, password.text, session.index) } } } } } } Item { id: loginpage Column { id: mainColumn anchors.centerIn: parent Item { id: userpic anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenterOffset: -1 anchors.bottom: parent.verticalCenter anchors.bottomMargin: m_biggerUserFrame ? -64 : -56 width: m_biggerUserFrame ? 238 : 190 height: width Item { width: m_biggerUserFrame ? 158 : 126 height: width anchors.centerIn: parent Rectangle { id: mask anchors.fill: parent anchors.centerIn: parent radius: 2 visible: false } LinearGradient { id: gradient anchors.fill: parent anchors.centerIn: parent z: -1 start: Qt.point(0,0) end: Qt.point(gradient.width, gradient.height) gradient: Gradient { GradientStop { position: 0.0; color: "#eeecee" } GradientStop { position: 1.0; color: "#a39ea3" } } } Image { id: avatar fillMode: Image.PreserveAspectCrop source: "" property string defaultPic: "Assets/user.png" onStatusChanged: { if (avatar.status == Image.Error) { avatar.source = avatar.defaultPic; } } anchors.fill: parent anchors.centerIn: parent layer.enabled: true layer.effect: OpacityMask { maskSource: mask } } } Image { source: m_biggerUserFrame ? "Assets/12238.png" : "Assets/12223.png" anchors.fill: parent anchors.centerIn: parent } } QQC2.Label { id: userNameLabel anchors.horizontalCenter: parent.horizontalCenter anchors.top: userpic.bottom text: "" color: "white" font.pixelSize: 23 font.kerning: false renderType: Text.NativeRendering font.hintingPreference: Font.PreferVerticalHinting layer.enabled: true layer.effect: DropShadow { verticalOffset: 1 color: "#ef000000" radius: 9 samples: 80 } } Item { id: loginbox anchors.horizontalCenter: parent.horizontalCenter anchors.top: userNameLabel.bottom anchors.topMargin: 8 width: 225 height: 24 QQC2.TextField { id: password anchors.fill: parent bottomPadding: 0 topPadding: 0 font.pointSize: 9 placeholderTextColor: "#555" background: Image { source: { if (password.focus) return "Assets/input-focus.png" if (password.hovered) return "Assets/input-hover.png" return "Assets/input.png" } } placeholderText: i18nd("aerothemeplasma-sddm-theme", "Password") selectByMouse: true echoMode : TextInput.Password inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText KeyNavigation.backtab: switchLayoutButton KeyNavigation.tab: loginButton KeyNavigation.down: { if (switchuser.enabled) { return switchuser } else { return accessbutton } } Keys.onPressed : (event) => { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { let index = listView.currentIndex let username = userModel.data(userModel.index(index, 0), Main.UserRoles.NameRole) if (username != null) { sddm.login(username, password.text, session.index) } event.accepted = true } else if ( event.matches(StandardKey.Undo) || event.matches(StandardKey.Redo) || event.matches(StandardKey.Cut) || event.matches(StandardKey.Copy) || event.matches(StandardKey.Paste) ) { // disable these events event.accepted = true } } } RowLayout { spacing: 2 anchors.top: password.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 2 visible: keyboard.capsLock && password.visible Image { id: iconSmall width: Kirigami.Units.iconSizes.small; height: Kirigami.Units.iconSizes.small; source: "./Assets/dialog-warning.png" sourceSize.width: iconSmall.width sourceSize.height: iconSmall.height } QQC2.Label { id: notificationsLabel font.pointSize: 9 text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Caps Lock is on"); width: implicitWidth renderType: Text.NativeRendering color: "white" } } QQC2.Button { id: loginButton anchors.left: password.right anchors.verticalCenter: password.verticalCenter anchors.verticalCenterOffset: -1 anchors.leftMargin: 4 width: 30 height: 30 background: Image { source: loginButton.pressed ? "Assets/gopressed.png" : (loginButton.focus || loginButton.hovered ? "Assets/gohover.png" : "Assets/go.png") } onClicked: { let index = listView.currentIndex let username = userModel.data(userModel.index(index, 0), Main.UserRoles.NameRole) if (username != null) { sddm.login(username, password.text, session.index) } } KeyNavigation.backtab: password KeyNavigation.tab: { if (switchuser.enabled) { return switchuser } else { return accessbutton } } KeyNavigation.down: { if (switchuser.enabled) { return switchuser } else { return accessbutton } } } } QQC2.Button { id: switchuser anchors.horizontalCenter: parent.horizontalCenter anchors.top: userpic.bottom anchors.topMargin: 124 //anchors.bottom: parent.bottom //anchors.bottomMargin: 332 width: 108 height: 28 background: Image { source: { if (switchuser.pressed) return "Assets/switch-user-button-active.png" if (switchuser.hovered && switchuser.focus) return "Assets/switch-user-button-hover-focus.png" if (switchuser.hovered && !switchuser.focus) return "Assets/switch-user-button-hover.png" if (!switchuser.hovered && switchuser.focus) return "Assets/switch-user-button-focus.png" return "Assets/switch-user-button.png" } } contentItem: Text { text: i18nd("aerothemeplasma-sddm-theme", "Switch User") color: "white" //font.family: mainfont.name font.pointSize: 11 font.kerning: false renderType: Text.NativeRendering font.hintingPreference: Font.PreferFullHinting horizontalAlignment : Text.AlignHCenter verticalAlignment : Text.AlignVCenter bottomPadding: 3 } KeyNavigation.backtab: password KeyNavigation.up: password KeyNavigation.tab: accessbutton KeyNavigation.down: accessbutton onClicked: { password.text = "" pages.currentIndex = Main.LoginPage.SelectUser } Keys.onReturnPressed: { clicked() event.accepted = true } } } } Item { id: loginfailedpage Keys.onEscapePressed: { pages.currentIndex = Main.LoginPage.Login } Image { id: currentMessageIcon anchors.right: currentMessage.left anchors.verticalCenter: currentMessage.verticalCenter anchors.verticalCenterOffset: -2 anchors.rightMargin: 11 source: "Assets/dialog-error.png" width: 32 height: 32 focus: false smooth: false } QQC2.Label { id: currentMessage anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenterOffset: 126 anchors.horizontalCenterOffset: 14 text: i18nd("aerothemeplasma-sddm-theme", "The user name or password is incorrect.") renderType: Text.NativeRendering Layout.alignment: Qt.AlignHCenter font.pointSize: 9 focus: false width: implicitWidth color: "white" horizontalAlignment: Text.AlignCenter layer.enabled: true layer.effect: DropShadow { horizontalOffset: 0 verticalOffset: 1 radius: 6 samples: 14 spread: 0.0001 color: "#bf000000" } } QQC2.Button { id: dismissButton anchors.top: currentMessage.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 46 width: 93 height: 28 background: Image { source: { if (dismissButton.pressed) return "Assets/button-active.png" if (dismissButton.hovered && dismissButton.focus) return "Assets/button-hover-focus.png" if (dismissButton.hovered && !dismissButton.focus) return "Assets/button-hover.png" if (!dismissButton.hovered && dismissButton.focus) return "Assets/button-focus.png" return "Assets/button.png" } } contentItem: Text { text: i18nd("aerothemeplasma-sddm-theme", "OK") color: "white" //font.family: mainfont.name font.pointSize: 11 horizontalAlignment : Text.AlignHCenter verticalAlignment : Text.AlignVCenter renderType: Text.NativeRendering bottomPadding: 3 rightPadding: 1 } onClicked: { pages.currentIndex = Main.LoginPage.Login } Keys.onReturnPressed: { clicked() event.accepted = true } } } } Image { id: branding anchors.bottom: parent.bottom anchors.bottomMargin: 23 anchors.horizontalCenter: parent.horizontalCenter source: Qt.resolvedUrl("Assets/branding-white.png") visible: pages.currentIndex != Main.LoginPage.Startup } SMOD.GenericButton { id: switchLayoutButton property int currentIndex: keyboard.currentLayout onCurrentIndexChanged: keyboard.currentLayout = currentIndex anchors { top: parent.top topMargin: 5 left: parent.left leftMargin: 7 } implicitWidth: 35 implicitHeight: 28 label.font.pointSize: 9 label.font.capitalization: Font.AllUppercase Accessible.description: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to change keyboard layout", "Switch layout") KeyNavigation.backtab: rebootButton KeyNavigation.tab: pages.currentIndex === Main.LoginPage.SelectUser ? listView : password KeyNavigation.down: pages.currentIndex === Main.LoginPage.SelectUser ? listView : password text: keyboard.layouts[currentIndex].shortName onClicked: currentIndex = (currentIndex + 1) % keyboard.layouts.length visible: keyboard.layouts.length > 1 && pages.currentIndex != Main.LoginPage.Startup } QQC2.CheckBox { id: accessbutton anchors.bottom: parent.bottom anchors.left: parent.left anchors.bottomMargin: 34 anchors.leftMargin: 34 width: 38 height: 28 visible: pages.currentIndex != Main.LoginPage.LoginFailed && pages.currentIndex != Main.LoginPage.Startup indicator.width: 0 indicator.height: 0 background: Image { source: { if (accessbutton.pressed) return "Assets/access-button-active.png" if (accessbutton.hovered && accessbutton.focus) return "Assets/access-button-hover-focus.png" if (accessbutton.hovered && !accessbutton.focus) return "Assets/access-button-hover.png" if (!accessbutton.hovered && accessbutton.focus) return "Assets/access-button-focus.png" return "Assets/access-button.png" } } contentItem: Item { anchors.centerIn: parent width: 24 height: 24 Image { anchors.centerIn: parent width: 24 height: 24 source: "Assets/12213.png" smooth: false } } enabled: !session.visible onToggled: { if(session.visible) session.close(); else session.open(); } Keys.onReturnPressed: { clicked() event.accepted = true } KeyNavigation.backtab: { if (pages.currentIndex === Main.LoginPage.SelectUser) { return listView } else if (switchuser.enabled) { return switchuser } return password } KeyNavigation.up: { if (pages.currentIndex === Main.LoginPage.Login && switchuser.enabled) { return switchuser } return accessbutton } KeyNavigation.tab: shutdownButton KeyNavigation.right: shutdownButton Item { anchors.bottom: parent.top anchors.left: parent.left anchors.bottomMargin: -32 visible: pages.currentIndex != Main.LoginPage.LoginFailed enabled: visible width: 128 height: 64 SMOD.Menu { id: session x: 0 y: -session.height + accessbutton.height + session.verticalPadding index: sessionModel.lastIndex function changeVal() { session.valueChanged(this.index); session.index = this.index; } function isIndex() { return session.index === this.index } Component.onCompleted: { for(var i = 0; i < sessionModel.count; i++) { const NameRole = sessionModel.KItemModels.KRoleNames.role("name"); const name = sessionModel.data(sessionModel.index(i, 0), NameRole); var menuitem = createMenuItem(); menuitem.text = name; menuitem.index = i; var func = isIndex.bind({index: i}); menuitem.checkable = true; menuitem.checked = Qt.binding(func); menuitem.triggered.connect(changeVal.bind({index: i})); session.addAction(menuitem); } } } } } Item { anchors.bottom: parent.bottom anchors.right: parent.right anchors.bottomMargin: 34 anchors.rightMargin: 30 visible: pages.currentIndex != Main.LoginPage.LoginFailed && pages.currentIndex != Main.LoginPage.Startup enabled: pages.currentIndex != Main.LoginPage.Startup width: 62 height: 28 QQC2.Button { id: shutdownButton anchors.bottom: parent.bottom anchors.left: parent.left width: 38 height: 28 background: Image { source: { if (shutdownButton.pressed) return "Assets/power-active.png" if (shutdownButton.hovered && shutdownButton.focus) return "Assets/power-hover-focus.png" if (shutdownButton.hovered && !shutdownButton.focus) return "Assets/power-hover.png" if (!shutdownButton.hovered && shutdownButton.focus) return "Assets/power-focus.png" return "Assets/power.png" } } contentItem: Item { anchors.centerIn: parent width: 24 height: 24 Image { anchors.centerIn: parent width: 24 height: 24 source: "Assets/power-glyph.png" smooth: false } } onClicked : sddm.powerOff() Keys.onReturnPressed: { clicked() event.accepted = true } KeyNavigation.backtab: accessbutton KeyNavigation.left: accessbutton KeyNavigation.tab: rebootButton KeyNavigation.right: rebootButton KeyNavigation.up: { if (pages.currentIndex === Main.LoginPage.Login && switchuser.enabled) { return switchuser } return shutdownButton } QQC2.ToolTip.visible: hovered QQC2.ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval QQC2.ToolTip.text: i18nd("aerothemeplasma-sddm-theme", "Shut down") } QQC2.Button { id: rebootButton anchors.bottom: parent.bottom anchors.left: shutdownButton.right visible: pages.currentIndex != Main.LoginPage.Startup width: 20 height: 28 background: Image { source: { if (rebootButton.pressed) return "Assets/12301.png" if (rebootButton.hovered && rebootButton.focus) return "Assets/12298.png" if (rebootButton.hovered && !rebootButton.focus) return "Assets/12300.png" if (!rebootButton.hovered && rebootButton.focus) return "Assets/12299.png" return "Assets/12302.png" } } contentItem: Item { anchors.centerIn: parent width: 9 height: 6 Image { anchors.centerIn: parent width: 9 height: 6 source: "Assets/power-glyph-arrow.png" smooth: false } } enabled: !powerMenu.visible onClicked: { if(powerMenu.visible) powerMenu.close(); else powerMenu.open(); } SMOD.Menu { id: powerMenu x: -powerMenu.width + parent.width //-parent.width + powerMenu.horizontalPadding y: -powerMenu.height //-powerMenu.height + rebootButton.height //+ powerMenu.verticalPadding Component.onCompleted: { var menuitem = powerMenu.createMenuItem(); menuitem.text = i18nd("aerothemeplasma-sddm-theme", "Restart"); menuitem.triggered.connect(() => { sddm.reboot() }); powerMenu.addAction(menuitem); powerMenu.addItem(powerMenu.createMenuSeparator()); if(sddm.canSuspend) { menuitem = powerMenu.createMenuItem(); menuitem.text = i18nd("aerothemeplasma-sddm-theme", "Sleep"); menuitem.triggered.connect(() => { sddm.suspend() }); powerMenu.addAction(menuitem); } if(sddm.canHibernate) { menuitem = powerMenu.createMenuItem(); menuitem.text = i18nd("aerothemeplasma-sddm-theme", "Hibernate"); menuitem.triggered.connect(() => { sddm.hibernate() }); powerMenu.addAction(menuitem); } if(sddm.canHybridSleep) { menuitem = powerMenu.createMenuItem(); menuitem.text = i18nd("aerothemeplasma-sddm-theme", "Hybrid Sleep"); menuitem.triggered.connect(() => { sddm.hybridSleep() }); powerMenu.addAction(menuitem); } menuitem = powerMenu.createMenuItem(); menuitem.text = i18nd("aerothemeplasma-sddm-theme", "Shut down"); menuitem.triggered.connect(() => { sddm.powerOff() }); powerMenu.addAction(menuitem); } } Keys.onReturnPressed: event => { clicked() event.accepted = true } KeyNavigation.backtab: shutdownButton KeyNavigation.left: shutdownButton KeyNavigation.up: { if (pages.currentIndex === Main.LoginPage.Login && switchuser.enabled) { return switchuser } return rebootButton } KeyNavigation.tab: switchLayoutButton } } Item { id: startuppage z: 99 anchors.fill: parent SequentialAnimation { id: seqanimation NumberAnimation { target: startuppage; property: "opacity"; to: 1; duration: 220; easing.type: Easing.Linear } NumberAnimation { target: startupimage; property: "opacity"; to: 1; duration: 650; easing.type: Easing.Linear } NumberAnimation { target: startupimage; property: "opacity"; to: 1; duration: 200; easing.type: Easing.Linear } NumberAnimation { target: startupimage2; property: "opacity"; to: 1; duration: 650; easing.type: Easing.Linear } NumberAnimation { target: startupimage3; property: "opacity"; to: 1; duration: 650; easing.type: Easing.Linear } NumberAnimation { target: startupimage4; property: "opacity"; to: 1; duration: 650; easing.type: Easing.Linear } NumberAnimation { target: startupimage4; property: "opacity"; to: 1; duration: 200; easing.type: Easing.Linear } ParallelAnimation { NumberAnimation { target: startupimage2; property: "opacity"; to: 0; duration: 650; easing.type: Easing.OutQuad } NumberAnimation { target: startupimage3; property: "opacity"; to: 0; duration: 650; easing.type: Easing.OutQuad } NumberAnimation { target: startupimage4; property: "opacity"; to: 0; duration: 650; easing.type: Easing.OutQuad } NumberAnimation { target: startupimage; property: "opacity"; to: 0; duration: 950; easing.type: Easing.OutQuad } } ScriptAction { script: { pages.startSingleUserMode(); } } NumberAnimation { target: startuppage; property: "opacity"; to: 0; duration: 650; easing.type: Easing.Linear } NumberAnimation { target: startupanimation; property: "opacity"; to: 0; duration: 650; easing.type: Easing.OutQuad } PropertyAction { target: executable; property: "startupEnabled"; value: false } } visible: executable.startupEnabled opacity: 1 Rectangle { color: "black" anchors.fill: parent } Item { id: startupanimation property int progress: 0 anchors.centerIn: parent Image { id: startupimage anchors.centerIn: parent source: Qt.resolvedUrl("./Assets/17000") opacity: 0 } Image { id: startupimage2 anchors.centerIn: parent source: Qt.resolvedUrl("./Assets/17001") opacity: 0 } Image { id: startupimage3 anchors.centerIn: parent source: Qt.resolvedUrl("./Assets/17002") opacity: 0 } Image { id: startupimage4 anchors.centerIn: parent source: Qt.resolvedUrl("./Assets/17003") opacity: 0 } } // to hide the cursor MouseArea { anchors.fill: parent cursorShape: Qt.BlankCursor } } }