mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-28 14:07:47 -04:00
Fix/3958 workspace indicator icon perf (#3961)
port 2.0
(cherry picked from commit b2e1817aad)
This commit is contained in:
1 parent
69fc822ffd
commit
d2ad778e6f
4 files changed
+57
-25
No files matched your search
@@ -83,7 +83,7 @@ BasePill {
|
||||
|
||||
function getWorkspaceIcons(ws) {
|
||||
_desktopEntriesUpdateTrigger;
|
||||
if (!root.opt("showWorkspaceApps") || !ws || !root.useNativeWorkspaces || ws.placeholder) {
|
||||
if (!root.opt("showWorkspaceApps") || !ws || !root.useNativeWorkspaces || ws.placeholder || !IconThemeService.ready) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -675,8 +675,8 @@ BasePill {
|
||||
const didReorder = wasDragging && root.dragTargetIndex >= 0 && root.dragTargetIndex !== root.dragSourceIndex;
|
||||
|
||||
if (didReorder) {
|
||||
const sourceWs = root.workspaceList[root.dragSourceIndex];
|
||||
const targetWs = root.workspaceList[root.dragTargetIndex];
|
||||
const sourceWs = root.recordOf(root.workspaceList[root.dragSourceIndex]);
|
||||
const targetWs = root.recordOf(root.workspaceList[root.dragTargetIndex]);
|
||||
|
||||
if (sourceWs && targetWs && sourceWs.id !== undefined && targetWs.idx !== undefined) {
|
||||
root.suppressShiftAnimation = true;
|
||||
@@ -983,6 +983,7 @@ BasePill {
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: loadedIcons.slice(0, root.opt("maxWorkspaceIcons"))
|
||||
comparisonMode: ObjectComparison.Structure
|
||||
}
|
||||
delegate: Item {
|
||||
width: root.appIconSize
|
||||
@@ -1141,6 +1142,7 @@ BasePill {
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: loadedIcons.slice(0, root.opt("maxWorkspaceIcons"))
|
||||
comparisonMode: ObjectComparison.Structure
|
||||
}
|
||||
delegate: Item {
|
||||
width: root.appIconSize
|
||||
@@ -1281,6 +1283,8 @@ BasePill {
|
||||
}
|
||||
readonly property var rootCurrentWorkspace: root.currentWorkspace
|
||||
onRootCurrentWorkspaceChanged: updateAllData()
|
||||
readonly property bool iconIndexReady: IconThemeService.ready
|
||||
onIconIndexReadyChanged: updateAllData()
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onBarConfigsChanged() {
|
||||
|
||||
@@ -40,6 +40,14 @@ function chainIndex(path, searchDirs, looseDirs) {
|
||||
return searchDirs.length + looseDirs.length;
|
||||
}
|
||||
|
||||
const LARGEST_PREFERRED_RASTER = 256;
|
||||
|
||||
function rasterScore(size) {
|
||||
if (size <= LARGEST_PREFERRED_RASTER)
|
||||
return LARGEST_PREFERRED_RASTER + size;
|
||||
return Math.max(0, LARGEST_PREFERRED_RASTER - size / 8);
|
||||
}
|
||||
|
||||
function score(path, searchDirs, looseDirs) {
|
||||
let s = 0;
|
||||
if (path.includes("/apps/"))
|
||||
@@ -59,7 +67,7 @@ function score(path, searchDirs, looseDirs) {
|
||||
} else {
|
||||
const m = path.match(/\/(\d+)(?:x\d+)?(?:@\d+x)?\//);
|
||||
if (m)
|
||||
s += Math.min(parseInt(m[1]), 999);
|
||||
s += rasterScore(parseInt(m[1]));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -61,25 +61,24 @@ QtObject {
|
||||
"minCount": showPadding ? paddingCount : 0,
|
||||
"showSpecial": showSpecial
|
||||
});
|
||||
if (CompositorService.ephemeralWorkspaces)
|
||||
return hyprlandSlotList(baseList);
|
||||
if (!showPadding || CompositorService.supportsPersistentWorkspaces || (useAqueous && baseList.length === 0))
|
||||
return baseList;
|
||||
return padWorkspaces(baseList);
|
||||
const slots = slotList(baseList);
|
||||
if (CompositorService.ephemeralWorkspaces || !showPadding || CompositorService.supportsPersistentWorkspaces || (useAqueous && baseList.length === 0))
|
||||
return slots;
|
||||
return padWorkspaces(slots);
|
||||
}
|
||||
|
||||
readonly property var realWorkspaces: workspaceList.filter(ws => ws && !recordOf(ws).placeholder)
|
||||
readonly property var realWorkspaces: workspaceList.map(ws => recordOf(ws)).filter(ws => ws && !ws.placeholder)
|
||||
readonly property bool hasWorkspaces: realWorkspaces.length > 0
|
||||
readonly property bool available: useNativeWorkspaces || (useExtWorkspace && hasWorkspaces)
|
||||
|
||||
onCompositorNameChanged: {
|
||||
_placeholderPool = [];
|
||||
_hyprSlotPool = {};
|
||||
_slotPool = {};
|
||||
}
|
||||
|
||||
// Hyprland creates/destroys workspaces on empty enter/leave; slots keyed by id keep delegate identity so pills animate instead of popping
|
||||
property var _hyprSlotPool: ({})
|
||||
readonly property Component _hyprSlotComponent: Component {
|
||||
property var _slotPool: ({})
|
||||
readonly property Component _slotComponent: Component {
|
||||
QtObject {
|
||||
property var ws: null
|
||||
}
|
||||
@@ -91,19 +90,27 @@ QtObject {
|
||||
return entry.ws;
|
||||
}
|
||||
|
||||
function _hyprSlot(key, ws) {
|
||||
let slot = _hyprSlotPool[key];
|
||||
if (!slot) {
|
||||
slot = _hyprSlotComponent.createObject(root);
|
||||
_hyprSlotPool[key] = slot;
|
||||
function slotList(raw) {
|
||||
const live = {};
|
||||
const slots = raw.map(ws => {
|
||||
const key = ws.id !== null && ws.id !== undefined && !ws.special ? ws.id : (ws.special ? "special:" : "name:") + (ws.name ?? "");
|
||||
let slot = _slotPool[key];
|
||||
if (!slot) {
|
||||
slot = _slotComponent.createObject(root);
|
||||
_slotPool[key] = slot;
|
||||
}
|
||||
if (slot.ws !== ws)
|
||||
slot.ws = ws;
|
||||
live[key] = true;
|
||||
return slot;
|
||||
});
|
||||
for (const key in _slotPool) {
|
||||
if (live[key])
|
||||
continue;
|
||||
_slotPool[key].destroy();
|
||||
delete _slotPool[key];
|
||||
}
|
||||
if (slot.ws !== ws)
|
||||
slot.ws = ws;
|
||||
return slot;
|
||||
}
|
||||
|
||||
function hyprlandSlotList(raw) {
|
||||
return raw.map(ws => _hyprSlot(ws.id > 0 ? ws.id : (ws.special ? "special:" : "name:") + (ws.name ?? ""), ws));
|
||||
return slots;
|
||||
}
|
||||
|
||||
// Stable placeholder instances so ScriptModel reuses padding delegates instead of recreating them on workspace churn
|
||||
|
||||
@@ -32,6 +32,19 @@ test("index keeps the existing category, root, format, size and tie priorities",
|
||||
assert.equal(build(ties).icon, ties[0]);
|
||||
});
|
||||
|
||||
test("index prefers rasters up to 256px over larger ones, and the smallest of those otherwise", () => {
|
||||
const cases = [
|
||||
["/system/hicolor/apps/1024x1024/icon.png", "/system/hicolor/apps/256x256/icon.png"],
|
||||
["/system/hicolor/apps/512x512/icon.png", "/system/hicolor/apps/128x128/icon.png"],
|
||||
["/system/hicolor/apps/1024x1024/icon.png", "/system/hicolor/apps/512x512/icon.png"],
|
||||
["/system/hicolor/apps/256x256/icon.png", "/system/hicolor/apps/scalable/icon.png"]
|
||||
];
|
||||
for (const [loser, winner] of cases) {
|
||||
assert.equal(build([loser, winner]).icon, winner);
|
||||
assert.equal(build([winner, loser]).icon, winner);
|
||||
}
|
||||
});
|
||||
|
||||
test("index bounds retained paths by resolvable names and handles object property names", () => {
|
||||
const paths = ["/user/theme/apps/icon.svg", "/user/theme/apps/16/icon.png", "/system/pixmaps/loose.xpm", "/user/theme/apps/__proto__.svg", "/user/theme/apps/constructor.png", "/user/theme/apps/not a name.svg"];
|
||||
const result = build(paths);
|
||||
|
||||
Reference in new issue
Block a user