mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-13 06:33:30 -04:00
feat(sessions): implement local user session switching functionality
- Core user is logged in tty1 while user two is in tty3, you can now seamlessly switch bewteen them New IPC options: - `dms ipc call sessions list` - `dms switch-user [target]` - New Powermenu switch users option
This commit is contained in:
@@ -81,6 +81,8 @@ DankModal {
|
||||
executeAction(action);
|
||||
}
|
||||
|
||||
signal switchUserRequested
|
||||
|
||||
function executeAction(action) {
|
||||
if (action === "lock") {
|
||||
close();
|
||||
@@ -92,6 +94,11 @@ DankModal {
|
||||
Quickshell.execDetached(["dms", "restart"]);
|
||||
return;
|
||||
}
|
||||
if (action === "switchuser") {
|
||||
close();
|
||||
switchUserRequested();
|
||||
return;
|
||||
}
|
||||
close();
|
||||
root.powerActionRequested(action, "", "");
|
||||
}
|
||||
@@ -216,6 +223,12 @@ DankModal {
|
||||
"label": I18n.tr("Restart DMS"),
|
||||
"key": "D"
|
||||
};
|
||||
case "switchuser":
|
||||
return {
|
||||
"icon": "switch_account",
|
||||
"label": I18n.tr("Switch User"),
|
||||
"key": "U"
|
||||
};
|
||||
default:
|
||||
return {
|
||||
"icon": "help",
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modals.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
DankModal {
|
||||
id: root
|
||||
|
||||
property bool lockOnSwitch: false
|
||||
|
||||
function showFromPowerMenu() {
|
||||
root.lockOnSwitch = false;
|
||||
SessionsService.refresh();
|
||||
open();
|
||||
}
|
||||
|
||||
function showFromLockScreen() {
|
||||
root.lockOnSwitch = true;
|
||||
SessionsService.refresh();
|
||||
open();
|
||||
}
|
||||
|
||||
function _formatTty(s) {
|
||||
if (s.tty && s.tty.length > 0)
|
||||
return s.tty;
|
||||
if (s.seat && s.seat.length > 0)
|
||||
return s.seat;
|
||||
return I18n.tr("remote");
|
||||
}
|
||||
|
||||
function _formatType(s) {
|
||||
if (!s.type || s.type.length === 0)
|
||||
return "";
|
||||
switch (s.type) {
|
||||
case "wayland":
|
||||
return "Wayland";
|
||||
case "x11":
|
||||
return "X11";
|
||||
case "tty":
|
||||
return "TTY";
|
||||
default:
|
||||
return s.type.charAt(0).toUpperCase() + s.type.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
function _doSwitch(sessionId, username) {
|
||||
if (root.lockOnSwitch && typeof SessionService !== "undefined" && SessionService.loginctlAvailable)
|
||||
SessionService.lock();
|
||||
SessionsService.activate(sessionId, null);
|
||||
close();
|
||||
}
|
||||
|
||||
layerNamespace: "dms:switch-user-modal"
|
||||
shouldBeVisible: false
|
||||
allowStacking: true
|
||||
modalWidth: 420
|
||||
modalHeight: contentLoader.item ? Math.min(540, contentLoader.item.implicitHeight + Theme.spacingM * 2) : 320
|
||||
enableShadow: true
|
||||
shouldHaveFocus: true
|
||||
onBackgroundClicked: close()
|
||||
|
||||
Connections {
|
||||
target: SessionsService
|
||||
function onSwitchRequested() {
|
||||
root.showFromPowerMenu();
|
||||
}
|
||||
}
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
implicitHeight: mainColumn.implicitHeight
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
anchors.rightMargin: Theme.spacingL
|
||||
anchors.topMargin: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "switch_account"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Switch User")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Select an active session to switch to. The current session stays running in the background.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
visible: SessionsService.otherSessions().length > 0
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
visible: SessionsService.otherSessions().length > 0
|
||||
|
||||
Repeater {
|
||||
model: SessionsService.otherSessions()
|
||||
|
||||
Rectangle {
|
||||
id: sessionRow
|
||||
required property var modelData
|
||||
width: parent.width
|
||||
height: 64
|
||||
radius: Theme.cornerRadius
|
||||
color: sessionMouse.containsMouse ? Theme.surfacePressed : Theme.surfaceContainerHighest
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "account_circle"
|
||||
size: Theme.iconSize + 4
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - 4 - chevron.width - Theme.spacingM * 2
|
||||
spacing: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: sessionRow.modelData.username
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const tty = root._formatTty(sessionRow.modelData);
|
||||
const type = root._formatType(sessionRow.modelData);
|
||||
const parts = [];
|
||||
if (type)
|
||||
parts.push(type);
|
||||
parts.push(I18n.tr("session %1").arg(sessionRow.modelData.sessionId));
|
||||
if (tty)
|
||||
parts.push(tty);
|
||||
return parts.join(" · ");
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: chevron
|
||||
name: "chevron_right"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: sessionMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root._doSwitch(sessionRow.modelData.sessionId, sessionRow.modelData.username)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
visible: SessionsService.otherSessions().length === 0
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: bodyCol.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHighest
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "info"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 2
|
||||
}
|
||||
|
||||
Column {
|
||||
id: bodyCol
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("No other active sessions on this seat")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("To sign in as a different user, log out and pick the account from the greeter. Creating a fresh session in parallel needs a multi-session greeter (greetd-flexiserver / GDM / LightDM).")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
layoutDirection: Qt.RightToLeft
|
||||
|
||||
DankButton {
|
||||
text: I18n.tr("Close")
|
||||
backgroundColor: Theme.surfaceVariantAlpha
|
||||
textColor: Theme.surfaceText
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
DankButton {
|
||||
visible: SessionsService.otherSessions().length === 0 && !root.lockOnSwitch
|
||||
text: I18n.tr("Log out")
|
||||
iconName: "logout"
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.primaryText
|
||||
onClicked: {
|
||||
if (typeof SessionService !== "undefined")
|
||||
SessionService.logout();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 1
|
||||
height: Theme.spacingS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user