diff --git a/quickshell/Modules/DIsland/IslandHostRegistry.qml b/quickshell/Common/IslandHostRegistry.qml similarity index 100% rename from quickshell/Modules/DIsland/IslandHostRegistry.qml rename to quickshell/Common/IslandHostRegistry.qml diff --git a/quickshell/Common/PopoutManager.qml b/quickshell/Common/PopoutManager.qml index 1b63194e2..85a706bbb 100644 --- a/quickshell/Common/PopoutManager.qml +++ b/quickshell/Common/PopoutManager.qml @@ -338,9 +338,102 @@ Singleton { _requestPopout(popout, tabIndex, triggerSource, true); } + function _islandBarBand(host, screen) { + const vertical = host.edge === "left" || host.edge === "right"; + if (host.embedded) { + const start = vertical ? host.hostOriginX : host.hostOriginY; + return { + "start": start, + "end": start + host.bandThickness + }; + } + if (host.freeMode) + return null; + + const extent = vertical ? screen.width : screen.height; + const instances = ShellLayout.forScreen(screen)?.instances ?? []; + let start = Infinity; + let end = -Infinity; + for (const instance of instances) { + if (instance.edge !== host.edge || instance.barId === host.barId || (instance.kind !== "bar" && instance.kind !== "frame") || instance.rowThickness <= 0) + continue; + const config = SettingsData.getBarConfig(instance.barId); + if (!config || config.enabled === false || config.visible === false) + continue; + const near = instance.rowOffset ?? 0; + const far = near + instance.rowThickness; + const bandStart = host.edge === "top" || host.edge === "left" ? near : extent - far; + const bandEnd = host.edge === "top" || host.edge === "left" ? far : extent - near; + start = Math.min(start, bandStart); + end = Math.max(end, bandEnd); + } + return end > start ? { + "start": start, + "end": end + } : null; + } + function getActiveSurfaces() { const results = []; + // The host registry covers embedded, standalone, and free Islands with their live visual bounds. + for (const key of Object.keys(IslandHostRegistry.hosts || {})) { + const host = IslandHostRegistry.hosts[key]; + const screen = host?.screen; + const controller = host?.islandController; + const snapVisible = controller?.expanded || (!host?.embedded && host?.motionRunning); + if (!screen?.name || !snapVisible || host.surfaceOpacity <= 0) + continue; + const rect = host.surfaceBodyRect?.(); + if (!rect || rect.width <= 0 || rect.height <= 0) + continue; + let x = rect.x; + let y = rect.y; + let width = rect.width; + let height = rect.height; + const barBand = _islandBarBand(host, screen); + if (barBand) { + switch (host.edge) { + case "top": + if (y < barBand.end && y + height > barBand.start) { + const inset = Math.max(0, Math.min(height, barBand.end - y)); + y += inset; + height -= inset; + } + break; + case "bottom": + if (y + height > barBand.start && y < barBand.end) + height = Math.max(0, barBand.start - y); + break; + case "left": + if (x < barBand.end && x + width > barBand.start) { + const inset = Math.max(0, Math.min(width, barBand.end - x)); + x += inset; + width -= inset; + } + break; + case "right": + if (x + width > barBand.start && x < barBand.end) + width = Math.max(0, barBand.start - x); + break; + } + } + const left = Math.max(0, x); + const top = Math.max(0, y); + const right = Math.min(screen.width, x + width); + const bottom = Math.min(screen.height, y + height); + if (right <= left || bottom <= top) + continue; + results.push({ + "name": "dms:dankisland-surface", + "type": "island", + "x": Math.round((screen.x ?? 0) + left), + "y": Math.round((screen.y ?? 0) + top), + "width": Math.round(right - left), + "height": Math.round(bottom - top) + }); + } + for (const screenName in currentPopoutsByScreen) { const popout = currentPopoutsByScreen[screenName]; if (!popout || !popout.shouldBeVisible)