diff --git a/roles/lmn_qgm/files/qgm-breeze/Main.qml b/roles/lmn_qgm/files/qgm-breeze/Main.qml new file mode 100644 index 0000000..c4342ff --- /dev/null +++ b/roles/lmn_qgm/files/qgm-breeze/Main.qml @@ -0,0 +1,633 @@ +/* + SPDX-FileCopyrightText: 2016 David Edmundson + + SPDX-License-Identifier: LGPL-2.0-or-later +*/ + +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQuick.Controls 2.15 as QQC2 +import QtGraphicalEffects 1.15 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents3 +import org.kde.plasma.extras 2.0 as PlasmaExtras + +import "../breeze" +import "../breeze/components" +import "../breeze/components/animation" + +// TODO: Once SDDM 0.19 is released and we are setting the font size using the +// SDDM KCM's syncing feature, remove the `config.fontSize` overrides here and +// the fontSize properties in various components, because the theme's default +// font size will be correctly propagated to the login screen + +PlasmaCore.ColorScope { + id: root + + // 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 + + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + + width: 1600 + height: 900 + + property string notificationMessage + + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + PlasmaCore.DataSource { + id: keystateSource + engine: "keystate" + connectedSources: "Caps Lock" + } + + Item { + id: wallpaper + anchors.fill: parent + Repeater { + model: screenModel + + Background { + x: geometry.x; y: geometry.y; width: geometry.width; height: geometry.height + sceneBackgroundType: config.type + sceneBackgroundColor: config.color + sceneBackgroundImage: config.background + } + } + } + + RejectPasswordAnimation { + id: rejectPasswordAnimation + target: mainStack + } + + MouseArea { + id: loginScreenRoot + anchors.fill: parent + + property bool uiVisible: true + property bool blockUI: mainStack.depth > 1 || userListComponent.mainPasswordBox.text.length > 0 || inputPanel.keyboardActive || config.type !== "image" + + hoverEnabled: true + drag.filterChildren: true + onPressed: uiVisible = true; + onPositionChanged: uiVisible = true; + onUiVisibleChanged: { + if (blockUI) { + fadeoutTimer.running = false; + } else if (uiVisible) { + fadeoutTimer.restart(); + } + } + onBlockUIChanged: { + if (blockUI) { + fadeoutTimer.running = false; + uiVisible = true; + } else { + fadeoutTimer.restart(); + } + } + + Keys.onPressed: { + uiVisible = true; + event.accepted = false; + } + + //takes one full hour for the ui to disappear + Timer { + id: fadeoutTimer + running: true + interval: 600000 + onTriggered: { + if (!loginScreenRoot.blockUI) { + userListComponent.mainPasswordBox.showPassword = false; + loginScreenRoot.uiVisible = false; + } + } + } + WallpaperFader { + visible: config.type === "image" + anchors.fill: parent + state: loginScreenRoot.uiVisible ? "on" : "off" + source: wallpaper + mainStack: mainStack + footer: footer + clock: clock + } + + DropShadow { + id: clockShadow + anchors.fill: clock + source: clock + visible: !softwareRendering + radius: 6 + samples: 14 + spread: 0.3 + color : "black" // shadows should always be black + Behavior on opacity { + OpacityAnimator { + duration: PlasmaCore.Units.veryLongDuration * 2 + easing.type: Easing.InOutQuad + } + } + } + + Clock { + id: clock + property Item shadow: clockShadow + visible: y > 0 + anchors.horizontalCenter: parent.horizontalCenter + y: (userListComponent.userList.y + mainStack.y)/2 - height/2 + Layout.alignment: Qt.AlignBaseline + } + + QQC2.StackView { + id: mainStack + anchors { + left: parent.left + right: parent.right + } + height: root.height + PlasmaCore.Units.gridUnit * 3 + + // If true (depends on the style and environment variables), hover events are always accepted + // and propagation stopped. This means the parent MouseArea won't get them and the UI won't be shown. + // Disable capturing those events while the UI is hidden to avoid that, while still passing events otherwise. + // One issue is that while the UI is visible, mouse activity won't keep resetting the timer, but when it + // finally expires, the next event should immediately set uiVisible = true again. + hoverEnabled: loginScreenRoot.uiVisible ? undefined : false + + focus: true //StackView is an implicit focus scope, so we need to give this focus so the item inside will have it + + Timer { + //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 + //it is fixed in 6d5b36b28907b16280ff78995fef764bb0c573db which will be 0.14 + //we need to call "window->activate()" *After* it's been shown. We can't control that in QML so we use a shoddy timer + //it's been this way for all Plasma 5.x without a huge problem + running: true + repeat: false + interval: 200 + onTriggered: mainStack.forceActiveFocus() + } + + initialItem: Login { + id: userListComponent + userListModel: userModel + loginScreenUiVisible: loginScreenRoot.uiVisible + userListCurrentIndex: userModel.lastIndex >= 0 ? userModel.lastIndex : 0 + lastUserName: userModel.lastUser + showUserList: { + if (!userListModel.hasOwnProperty("count") + || !userListModel.hasOwnProperty("disableAvatarsThreshold")) { + return false + } + + if (userListModel.count === 0 ) { + return false + } + + if (userListModel.hasOwnProperty("containsAllUsers") && !userListModel.containsAllUsers) { + return false + } + + return userListModel.count <= userListModel.disableAvatarsThreshold + } + + notificationMessage: { + const parts = []; + if (keystateSource.data["Caps Lock"]["Locked"]) { + parts.push(i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Caps Lock is on")); + } + if (root.notificationMessage) { + parts.push(root.notificationMessage); + } + return parts.join(" • "); + } + + actionItemsVisible: !inputPanel.keyboardActive + actionItems: [ + ActionButton { + iconSource: "system-suspend" + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Suspend to RAM", "Sleep") + fontSize: parseInt(config.fontSize) + 1 + onClicked: sddm.suspend() + enabled: sddm.canSuspend + }, + ActionButton { + iconSource: "system-reboot" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Restart") + fontSize: parseInt(config.fontSize) + 1 + onClicked: sddm.reboot() + enabled: sddm.canReboot + }, + ActionButton { + iconSource: "system-shutdown" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down") + fontSize: parseInt(config.fontSize) + 1 + onClicked: sddm.powerOff() + enabled: sddm.canPowerOff + }, + ActionButton { + iconSource: "system-user-prompt" + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "For switching to a username and password prompt", "Other…") + fontSize: parseInt(config.fontSize) + 1 + onClicked: mainStack.push(userPromptComponent) + enabled: true + visible: !userListComponent.showUsernamePrompt + }] + + onLoginRequest: { + root.notificationMessage = "" + sddm.login(username, password, sessionButton.currentIndex) + } + } + + Behavior on opacity { + OpacityAnimator { + duration: PlasmaCore.Units.longDuration + } + } + + readonly property real zoomFactor: 3 + + popEnter: Transition { + ScaleAnimator { + from: mainStack.zoomFactor + to: 1 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + OpacityAnimator { + from: 0 + to: 1 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + } + + popExit: Transition { + ScaleAnimator { + from: 1 + to: 0 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + OpacityAnimator { + from: 1 + to: 0 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + } + + pushEnter: Transition { + ScaleAnimator { + from: 0 + to: 1 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + OpacityAnimator { + from: 0 + to: 1 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + } + + pushExit: Transition { + ScaleAnimator { + from: 1 + to: mainStack.zoomFactor + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + OpacityAnimator { + from: 1 + to: 0 + duration: PlasmaCore.Units.longDuration * (mainStack.zoomFactor / 2) + easing.type: Easing.OutCubic + } + } + } + + Loader { + id: inputPanel + state: "hidden" + property bool keyboardActive: item ? item.active : false + onKeyboardActiveChanged: { + if (keyboardActive) { + state = "visible" + // Otherwise the password field loses focus and virtual keyboard + // keystrokes get eaten + userListComponent.mainPasswordBox.forceActiveFocus(); + } else { + state = "hidden"; + } + } + + source: Qt.platform.pluginName.includes("wayland") ? "../breeze/components/VirtualKeyboard_wayland.qml" : "../breeze/components/VirtualKeyboard.qml" + anchors { + left: parent.left + right: parent.right + } + + function showHide() { + state = state === "hidden" ? "visible" : "hidden"; + } + + states: [ + State { + name: "visible" + PropertyChanges { + target: mainStack + y: Math.min(0, root.height - inputPanel.height - userListComponent.visibleBoundary) + } + PropertyChanges { + target: inputPanel + y: root.height - inputPanel.height + opacity: 1 + } + }, + State { + name: "hidden" + PropertyChanges { + target: mainStack + y: 0 + } + PropertyChanges { + target: inputPanel + y: root.height - root.height/4 + opacity: 0 + } + } + ] + transitions: [ + Transition { + from: "hidden" + to: "visible" + SequentialAnimation { + ScriptAction { + script: { + inputPanel.item.activated = true; + Qt.inputMethod.show(); + } + } + ParallelAnimation { + NumberAnimation { + target: mainStack + property: "y" + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: inputPanel + property: "y" + duration: PlasmaCore.Units.longDuration + easing.type: Easing.OutQuad + } + OpacityAnimator { + target: inputPanel + duration: PlasmaCore.Units.longDuration + easing.type: Easing.OutQuad + } + } + } + }, + Transition { + from: "visible" + to: "hidden" + SequentialAnimation { + ParallelAnimation { + NumberAnimation { + target: mainStack + property: "y" + 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(); + } + } + } + } + ] + } + + Component { + id: userPromptComponent + Login { + showUsernamePrompt: true + notificationMessage: root.notificationMessage + loginScreenUiVisible: loginScreenRoot.uiVisible + fontSize: parseInt(config.fontSize) + 2 + + // using a model rather than a QObject list to avoid QTBUG-75900 + userListModel: ListModel { + ListElement { + name: "" + iconSource: "" + } + Component.onCompleted: { + // as we can't bind inside ListElement + setProperty(0, "name", i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Type in Username and Password")); + } + } + + onLoginRequest: { + root.notificationMessage = "" + sddm.login(username, password, sessionButton.currentIndex) + } + + actionItemsVisible: !inputPanel.keyboardActive + actionItems: [ + ActionButton { + iconSource: "system-suspend" + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Suspend to RAM", "Sleep") + fontSize: parseInt(config.fontSize) + 1 + onClicked: sddm.suspend() + enabled: sddm.canSuspend + }, + ActionButton { + iconSource: "system-reboot" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Restart") + fontSize: parseInt(config.fontSize) + 1 + onClicked: sddm.reboot() + enabled: sddm.canReboot + }, + ActionButton { + iconSource: "system-shutdown" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down") + fontSize: parseInt(config.fontSize) + 1 + onClicked: sddm.powerOff() + enabled: sddm.canPowerOff + }, + ActionButton { + iconSource: "system-user-list" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "List Users") + fontSize: parseInt(config.fontSize) + 1 + onClicked: mainStack.pop() + } + ] + } + + } + + + DropShadow { + id: logoShadow + anchors.fill: logo + source: logo + visible: !softwareRendering && config.showlogo === "shown" + horizontalOffset: 1 + verticalOffset: 1 + radius: 6 + samples: 14 + spread: 0.3 + color : "black" // shadows should always be black + opacity: loginScreenRoot.uiVisible ? 0 : 1 + Behavior on opacity { + //OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)" + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + Image { + id: logo + visible: config.showlogo === "shown" + source: config.logo + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: footer.top + anchors.bottomMargin: PlasmaCore.Units.largeSpacing + asynchronous: true + sourceSize.height: height + opacity: loginScreenRoot.uiVisible ? 0 : 1 + fillMode: Image.PreserveAspectFit + height: Math.round(PlasmaCore.Units.gridUnit * 3.5) + Behavior on opacity { + // OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)" + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + //Footer + RowLayout { + id: footer + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: PlasmaCore.Units.smallSpacing + } + + Behavior on opacity { + OpacityAnimator { + duration: PlasmaCore.Units.longDuration + } + } + + PlasmaComponents3.ToolButton { + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard") + font.pointSize: config.fontSize + icon.name: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off" + onClicked: { + // Otherwise the password field loses focus and virtual keyboard + // keystrokes get eaten + userListComponent.mainPasswordBox.forceActiveFocus(); + inputPanel.showHide() + } + visible: inputPanel.status === Loader.Ready + } + + KeyboardButton { + font.pointSize: config.fontSize + + onKeyboardLayoutChanged: { + // Otherwise the password field loses focus and virtual keyboard + // keystrokes get eaten + userListComponent.mainPasswordBox.forceActiveFocus(); + } + } + + SessionButton { + id: sessionButton + font.pointSize: config.fontSize + + onSessionChanged: { + // Otherwise the password field loses focus and virtual keyboard + // keystrokes get eaten + userListComponent.mainPasswordBox.forceActiveFocus(); + } + } + + + Item { + Layout.fillWidth: true + } + + Text { + color: "#ffffff" + text: qsTr("Netzwerkrechner - ") + sddm.hostName + font.pixelSize: 16 + anchors.horizontalCenter: parent.horizontalCenter + } + + Battery { + fontSize: config.fontSize + } + } + } + + Connections { + target: sddm + function onLoginFailed() { + notificationMessage = i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Login Failed") + footer.enabled = true + mainStack.enabled = true + userListComponent.userList.opacity = 1 + rejectPasswordAnimation.start() + } + function onLoginSucceeded() { + //note SDDM will kill the greeter at some random point after this + //there is no certainty any transition will finish, it depends on the time it + //takes to complete the init + mainStack.opacity = 0 + footer.opacity = 0 + } + } + + onNotificationMessageChanged: { + if (notificationMessage) { + notificationResetTimer.start(); + } + } + + Timer { + id: notificationResetTimer + interval: 3000 + onTriggered: notificationMessage = "" + } +} diff --git a/roles/lmn_qgm/files/qgm-breeze/metadata.desktop b/roles/lmn_qgm/files/qgm-breeze/metadata.desktop new file mode 100644 index 0000000..d553a12 --- /dev/null +++ b/roles/lmn_qgm/files/qgm-breeze/metadata.desktop @@ -0,0 +1,16 @@ +[SddmGreeterTheme] +Name=QG Breeze +Description=Breeze Theme using Debian artwork +Description[fr]=Thème brise utilisant l’apparence Debian +Author=Adapted by the Debian Qt/KDE Team from the KDE Visual Design Group work +Copyright=(c) 2014, David Edmundson +License=CC-BY-SA +Type=sddm-theme +Version=0.1 +Website=https://github.com/sddm/sddm +Screenshot=preview.png +MainScript=Main.qml +ConfigFile=theme.conf +TranslationsDirectory=translations +Theme-Id=qgm-breeze +Theme-API=2.0 diff --git a/roles/lmn_qgm/files/qgm-breeze/theme.conf b/roles/lmn_qgm/files/qgm-breeze/theme.conf new file mode 100644 index 0000000..2f5e193 --- /dev/null +++ b/roles/lmn_qgm/files/qgm-breeze/theme.conf @@ -0,0 +1,8 @@ +[General] +showlogo=hidden +logo=/usr/share/sddm/themes/breeze/default-logo.svg +type=image +color=#1d99f3 +fontSize=12 +background=/usr/local/share/qgm/qgm_background.jpg +needsFullUserModel=false