Open the windows you open together, together
Arrange the desktop, run "Save Layout as Project" from the launcher, name it. "Open Project" lays it out again on free workspaces, so it never lands on top of what you are already doing. Saved layouts are listed on the Desktop settings page, which is where they are removed. Recorded rather than written by hand, and a terminal's directory is most of why it is worth having: without it a project opens three terminals in your home folder and you change directory three times. This machine had two terminals in the same project when it was written, and reopening there is the difference between a layout and a working desktop. Four things had to be found by running it, none of which reading would have shown. A terminal's directory is not the terminal's working directory -- that is where it was launched from. The shell inside it is what has been cd'd. Reading the wrong one looked correct for exactly as long as the terminals under test had been started from the right place, which they had. gtk-launch cannot place a window. It activates over D-Bus, so the process Hyprland started exits and a [workspace N silent] rule has nothing left to apply to; Nautilus landed on whatever workspace was in front of you. The Exec line from the desktop entry is run directly instead. But DBusActivatable applications do the same thing regardless, so the window is found afterwards and moved by address -- which also means a window that never appeared is reported rather than assumed. /proc/PID/task/PID/children is a file of pids, not a directory. Listing it as one always raised, so the fast path was never once taken and everything went through pgrep. And kitty's --directory needs an equals sign or the short -d; the space-separated long form is accepted and silently ignored. The contract exercises a save and open round trip against a stubbed compositor, and reads a terminal's directory out of a real process tree rather than grepping the source for a shell name -- an earlier version passed against a helper that had been changed back, because the constant was still there. Claude-Session: https://claude.ai/code/session_01Q84axqUE5inJhf5Jz9CFy1
This commit is contained in:
@@ -15,6 +15,10 @@ import qs.services
|
||||
SettingsPage {
|
||||
id: root
|
||||
|
||||
// Which project is one click from being forgotten. Same in-place confirm the
|
||||
// SSH Keys and Snapshots pages use.
|
||||
property string confirmingProject: ""
|
||||
|
||||
// Turning the last screen off would leave no dock anywhere and no obvious
|
||||
// way back, so the final one cannot be removed -- it collapses to "every
|
||||
// screen" instead, which is the same thing on one display and recoverable
|
||||
@@ -185,6 +189,80 @@ SettingsPage {
|
||||
ToggleRow { setting: "hyprlandDonationNag"; divider: false }
|
||||
}
|
||||
|
||||
// Saved here, not created here. A layout is worth recording at the moment
|
||||
// you have it right, so saving is a launcher command; this is where the
|
||||
// ones you kept are reviewed and the ones you did not are removed.
|
||||
SettingsCard {
|
||||
title: "Projects"
|
||||
subtitle: Projects.projects.length > 0
|
||||
? "Saved window layouts. Opening one claims free workspaces, so it never lands on top of what you are doing."
|
||||
: "No saved layouts yet. Arrange your windows, then run \"Save Layout as Project\" from the launcher."
|
||||
|
||||
Repeater {
|
||||
model: Projects.projects
|
||||
|
||||
delegate: SettingRow {
|
||||
id: projectRow
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
readonly property string projectName: String(projectRow.modelData.name ?? "")
|
||||
readonly property bool confirming: root.confirmingProject === projectRow.projectName
|
||||
|
||||
label: projectRow.projectName
|
||||
detail: projectRow.confirming
|
||||
? "Forgetting this only removes the layout. Nothing that is open closes."
|
||||
: projectRow.modelData.windows + " windows across "
|
||||
+ projectRow.modelData.workspaces + " workspaces — "
|
||||
+ (projectRow.modelData.applications ?? []).join(", ")
|
||||
divider: projectRow.index < Projects.projects.length - 1
|
||||
controlWidth: 210
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 8
|
||||
|
||||
SettingsButton {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !projectRow.confirming
|
||||
text: "Open"
|
||||
enabled: !Projects.busy
|
||||
onClicked: Projects.open(projectRow.projectName)
|
||||
}
|
||||
|
||||
SettingsButton {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: projectRow.confirming
|
||||
text: "Forget it"
|
||||
tone: "danger"
|
||||
enabled: !Projects.busy
|
||||
onClicked: {
|
||||
root.confirmingProject = "";
|
||||
Projects.remove(projectRow.projectName);
|
||||
}
|
||||
}
|
||||
|
||||
SettingsButton {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: projectRow.confirming ? "Keep" : "Forget"
|
||||
enabled: !Projects.busy
|
||||
onClicked: root.confirmingProject =
|
||||
projectRow.confirming ? "" : projectRow.projectName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextRow {
|
||||
visible: Projects.lastError !== ""
|
||||
label: "Problem"
|
||||
detail: Projects.lastError
|
||||
divider: false
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "Workspaces & focus"
|
||||
subtitle: "Hyprland's workspaces are created and destroyed as you use them, so there is no fixed count to set."
|
||||
|
||||
Reference in New Issue
Block a user