1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-15 08:42:47 -04:00

workspace/ext-ws: drop custom ext-workspace in favor of quickshell

WindowManager implementation
This commit is contained in:
bbedward
2026-05-14 10:34:35 -04:00
parent 71438530a8
commit fb5198fd0b
11 changed files with 48 additions and 3227 deletions
@@ -4,6 +4,7 @@ import Quickshell
import Quickshell.Widgets
import Quickshell.Hyprland
import Quickshell.I3
import Quickshell.WindowManager
import qs.Common
import qs.Services
import qs.Widgets
@@ -86,7 +87,22 @@ Item {
}
}
readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle && ExtWorkspaceService.extWorkspaceAvailable)
readonly property var extProjection: (useExtWorkspace && parentScreen) ? WindowManager.screenProjection(parentScreen) : null
readonly property bool useExtWorkspace: {
if (Quickshell.env("DMS_FORCE_EXTWS") === "1")
return (WindowManager.windowsets?.length ?? 0) > 0;
switch (CompositorService.compositor) {
case "niri":
case "hyprland":
case "dwl":
case "sway":
case "scroll":
case "miracle":
return false;
default:
return (WindowManager.windowsets?.length ?? 0) > 0;
}
}
Connections {
target: DesktopEntries
@@ -361,7 +377,7 @@ Item {
"id": "",
"name": "",
"active": false,
"hidden": true
"_placeholder": true
};
} else if (CompositorService.isNiri) {
placeholder = {
@@ -493,33 +509,21 @@ Item {
}
function getExtWorkspaceWorkspaces() {
const groups = ExtWorkspaceService.groups;
if (!ExtWorkspaceService.extWorkspaceAvailable || groups.length === 0) {
return [
{
"id": "1",
"name": "1",
"active": false
}
];
}
const fallback = [
{
"id": "1",
"name": "1",
"active": false
}
];
if (!extProjection)
return fallback;
const group = groups.find(g => g.outputs && g.outputs.includes(root.screenName));
if (!group || !group.workspaces) {
return [
{
"id": "1",
"name": "1",
"active": false
}
];
}
let visible = group.workspaces.filter(ws => !ws.hidden);
let visible = extProjection.windowsets.filter(ws => ws.shouldDisplay);
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0);
if (hasValidCoordinates) {
visible = visible.sort((a, b) => {
visible = visible.slice().sort((a, b) => {
const coordsA = a.coordinates || [0, 0];
const coordsB = b.coordinates || [0, 0];
if (coordsA[0] !== coordsB[0])
@@ -528,33 +532,14 @@ Item {
});
}
visible = visible.map(ws => ({
id: ws.id,
name: ws.name,
coordinates: ws.coordinates,
state: ws.state,
active: ws.active,
urgent: ws.urgent,
hidden: ws.hidden,
groupID: group.id
}));
return visible.length > 0 ? visible : [
{
"id": "1",
"name": "1",
"active": false
}
];
return visible.length > 0 ? visible : fallback;
}
function getExtWorkspaceActiveWorkspace() {
if (!ExtWorkspaceService.extWorkspaceAvailable) {
return 1;
}
const activeWs = ExtWorkspaceService.getActiveWorkspaceForOutput(root.screenName);
return activeWs ? (activeWs.id || activeWs.name || "1") : "1";
if (!extProjection)
return "";
const activeWs = extProjection.windowsets.find(ws => ws.active);
return activeWs ? (activeWs.id || activeWs.name || "") : "";
}
readonly property real dpr: parentScreen ? CompositorService.getScreenScale(parentScreen) : 1
@@ -566,7 +551,7 @@ Item {
function getRealWorkspaces() {
return root.workspaceList.filter(ws => {
if (useExtWorkspace)
return ws && (ws.id !== "" || ws.name !== "") && !ws.hidden;
return ws && !ws._placeholder;
if (CompositorService.isNiri)
return ws && ws.idx !== -1;
if (CompositorService.isHyprland)
@@ -583,8 +568,9 @@ Item {
if (!data)
return;
if (root.useExtWorkspace && (data.id || data.name)) {
ExtWorkspaceService.activateWorkspace(data.id || data.name, data.groupID || "");
if (root.useExtWorkspace) {
if (typeof data.activate === "function")
data.activate();
return;
}
@@ -649,7 +635,8 @@ Item {
}
const nextWorkspace = realWorkspaces[nextIndex];
ExtWorkspaceService.activateWorkspace(nextWorkspace.id || nextWorkspace.name, nextWorkspace.groupID || "");
if (typeof nextWorkspace.activate === "function")
nextWorkspace.activate();
} else if (CompositorService.isNiri) {
const realWorkspaces = getRealWorkspaces();
if (realWorkspaces.length < 2) {
@@ -1013,7 +1000,7 @@ Item {
}
property bool isPlaceholder: {
if (root.useExtWorkspace)
return !!(modelData && modelData.hidden);
return !!(modelData && modelData._placeholder);
if (CompositorService.isNiri)
return !!(modelData && modelData.idx === -1);
if (CompositorService.isHyprland)
@@ -1313,8 +1300,9 @@ Item {
return;
if (mouse.button === Qt.LeftButton) {
if (root.useExtWorkspace && (modelData?.id || modelData?.name)) {
ExtWorkspaceService.activateWorkspace(modelData.id || modelData.name, modelData.groupID || "");
if (root.useExtWorkspace) {
if (typeof modelData?.activate === "function")
modelData.activate();
} else if (CompositorService.isNiri) {
if (modelData && modelData.id !== undefined) {
NiriService.switchToWorkspace(modelData.id);
@@ -1941,9 +1929,9 @@ Item {
}
}
Connections {
target: ExtWorkspaceService
target: WindowManager
enabled: root.useExtWorkspace
function onStateChanged() {
function onWindowsetsChanged() {
delegateRoot.updateAllData();
}
}
@@ -1952,9 +1940,6 @@ Item {
}
Component.onCompleted: {
if (useExtWorkspace && !DMSService.activeSubscriptions.includes("extworkspace")) {
DMSService.addSubscription("extworkspace");
}
_updateBlurRegistration();
}
+2 -12
View File
@@ -23,7 +23,6 @@ Singleton {
property bool isConnected: false
property bool isConnecting: false
property bool subscribeConnected: false
readonly property bool forceExtWorkspace: false
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
@@ -53,7 +52,6 @@ Singleton {
signal dwlStateUpdate(var data)
signal brightnessStateUpdate(var data)
signal brightnessDeviceUpdate(var device)
signal extWorkspaceStateUpdate(var data)
signal wlrOutputStateUpdate(var data)
signal evdevStateUpdate(var data)
signal gammaStateUpdate(var data)
@@ -288,7 +286,7 @@ Singleton {
function removeSubscription(service) {
if (activeSubscriptions.includes("all")) {
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "extworkspace", "browser", "location"];
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "browser", "location"];
const filtered = allServices.filter(s => s !== service);
subscribe(filtered);
} else {
@@ -310,7 +308,7 @@ Singleton {
excludeServices = [excludeServices];
}
const allServices = ["network", "loginctl", "freedesktop", "gamma", "theme.auto", "bluetooth", "cups", "dwl", "brightness", "extworkspace", "browser", "dbus", "location"];
const allServices = ["network", "loginctl", "freedesktop", "gamma", "theme.auto", "bluetooth", "cups", "dwl", "brightness", "browser", "dbus", "location"];
const filtered = allServices.filter(s => !excludeServices.includes(s));
subscribe(filtered);
}
@@ -364,8 +362,6 @@ Singleton {
if (data.device) {
brightnessDeviceUpdate(data.device);
}
} else if (service === "extworkspace") {
extWorkspaceStateUpdate(data);
} else if (service === "wlroutput") {
wlrOutputStateUpdate(data);
} else if (service === "evdev") {
@@ -752,12 +748,6 @@ Singleton {
});
}
function renameWorkspace(name, callback) {
sendRequest("extworkspace.renameWorkspace", {
"name": name
}, callback);
}
function sysupdateGetState(callback) {
sendRequest("sysupdate.getState", null, callback);
}
-279
View File
@@ -1,279 +0,0 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.Services
Singleton {
id: root
readonly property var log: Log.scoped("ExtWorkspaceService")
property bool extWorkspaceAvailable: false
property var groups: []
property var _cachedWorkspaces: ({})
signal stateChanged
Connections {
target: DMSService
function onCapabilitiesReceived() {
checkCapabilities();
}
function onConnectionStateChanged() {
if (DMSService.isConnected) {
checkCapabilities();
} else {
extWorkspaceAvailable = false;
}
}
function onExtWorkspaceStateUpdate(data) {
if (extWorkspaceAvailable) {
handleStateUpdate(data);
}
}
}
Component.onCompleted: {
if (DMSService.dmsAvailable) {
checkCapabilities();
}
}
function checkCapabilities() {
if (!DMSService.capabilities || !Array.isArray(DMSService.capabilities)) {
extWorkspaceAvailable = false;
return;
}
const hasExtWorkspace = DMSService.capabilities.includes("extworkspace");
if (hasExtWorkspace && !extWorkspaceAvailable) {
if (typeof CompositorService !== "undefined") {
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle);
if (!useExtWorkspace) {
log.info("ext-workspace available but compositor has native support");
extWorkspaceAvailable = false;
return;
}
}
extWorkspaceAvailable = true;
log.info("ext-workspace capability detected");
DMSService.addSubscription("extworkspace");
requestState();
} else if (!hasExtWorkspace) {
extWorkspaceAvailable = false;
}
}
function requestState() {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return;
}
DMSService.sendRequest("extworkspace.getState", null, response => {
if (response.result) {
handleStateUpdate(response.result);
}
});
}
function handleStateUpdate(state) {
groups = state.groups || [];
if (groups.length === 0) {
log.warn("Received empty workspace groups from backend");
} else {
log.debug("Updated with", groups.length, "workspace groups");
}
stateChanged();
}
function activateWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return;
}
DMSService.sendRequest("extworkspace.activateWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
log.warn("activateWorkspace error:", response.error);
}
});
}
function deactivateWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return;
}
DMSService.sendRequest("extworkspace.deactivateWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
log.warn("deactivateWorkspace error:", response.error);
}
});
}
function removeWorkspace(workspaceID, groupID = "") {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return;
}
DMSService.sendRequest("extworkspace.removeWorkspace", {
"workspaceID": workspaceID,
"groupID": groupID
}, response => {
if (response.error) {
log.warn("removeWorkspace error:", response.error);
}
});
}
function createWorkspace(groupID, name) {
if (!DMSService.isConnected || !extWorkspaceAvailable) {
return;
}
DMSService.sendRequest("extworkspace.createWorkspace", {
"groupID": groupID,
"name": name
}, response => {
if (response.error) {
log.warn("createWorkspace error:", response.error);
}
});
}
function getGroupForOutput(outputName) {
for (const group of groups) {
if (group.outputs && group.outputs.includes(outputName)) {
return group;
}
}
return null;
}
function getWorkspacesForOutput(outputName) {
const group = getGroupForOutput(outputName);
return group ? (group.workspaces || []) : [];
}
function getActiveWorkspaces() {
const active = [];
for (const group of groups) {
if (!group.workspaces)
continue;
for (const ws of group.workspaces) {
if (ws.active) {
active.push({
workspace: ws,
group: group,
outputs: group.outputs || []
});
}
}
}
return active;
}
function getActiveWorkspaceForOutput(outputName) {
const group = getGroupForOutput(outputName);
if (!group || !group.workspaces)
return null;
for (const ws of group.workspaces) {
if (ws.active) {
return ws;
}
}
return null;
}
function getVisibleWorkspaces(outputName) {
const workspaces = getWorkspacesForOutput(outputName);
let visible = workspaces.filter(ws => !ws.hidden);
const hasValidCoordinates = visible.some(ws => ws.coordinates && ws.coordinates.length > 0);
if (hasValidCoordinates) {
visible = visible.sort((a, b) => {
const coordsA = a.coordinates || [0, 0];
const coordsB = b.coordinates || [0, 0];
if (coordsA[0] !== coordsB[0])
return coordsA[0] - coordsB[0];
return coordsA[1] - coordsB[1];
});
}
const cacheKey = outputName;
if (!_cachedWorkspaces[cacheKey]) {
_cachedWorkspaces[cacheKey] = {
workspaces: [],
lastNames: []
};
}
const cache = _cachedWorkspaces[cacheKey];
const currentNames = visible.map(ws => ws.name || ws.id);
const namesChanged = JSON.stringify(cache.lastNames) !== JSON.stringify(currentNames);
if (namesChanged || cache.workspaces.length !== visible.length) {
cache.workspaces = visible.map(ws => ({
id: ws.id,
name: ws.name,
coordinates: ws.coordinates,
state: ws.state,
active: ws.active,
urgent: ws.urgent,
hidden: ws.hidden
}));
cache.lastNames = currentNames;
return cache.workspaces;
}
for (let i = 0; i < visible.length; i++) {
const src = visible[i];
const dst = cache.workspaces[i];
dst.id = src.id;
dst.name = src.name;
dst.coordinates = src.coordinates;
dst.state = src.state;
dst.active = src.active;
dst.urgent = src.urgent;
dst.hidden = src.hidden;
}
return cache.workspaces;
}
function getUrgentWorkspaces() {
const urgent = [];
for (const group of groups) {
if (!group.workspaces)
continue;
for (const ws of group.workspaces) {
if (ws.urgent) {
urgent.push({
workspace: ws,
group: group,
outputs: group.outputs || []
});
}
}
}
return urgent;
}
function switchToWorkspace(outputName, workspaceName) {
const workspaces = getWorkspacesForOutput(outputName);
for (const ws of workspaces) {
if (ws.name === workspaceName || ws.id === workspaceName) {
activateWorkspace(ws.name || ws.id);
return;
}
}
log.warn("workspace not found:", workspaceName);
}
}