//@ pragma IconTheme Papirus pragma ComponentBehavior: Bound import QtQuick import Quickshell import Quickshell.Io import Quickshell.Wayland import Quickshell.Widgets import Quickshell.Services.UPower ShellRoot { id: shell // Connector name of the monitor that hosts the interactive nuguland // surfaces (bar, OSD, toasts). Set e.g. "DP-1" to pin them; left empty it // falls back to the first connected screen. The wallpaper stays on every // screen; interactive security prompts stay on the primary screen. property string primaryOutput: "" readonly property var primaryScreens: { const screens = Quickshell.screens; const want = String(shell.primaryOutput || ""); for (let i = 0; i < screens.length; i++) if (want.length === 0 || String(screens[i].name) === want) return [screens[i]]; return []; } readonly property string primaryScreenName: primaryScreens.length > 0 ? String(primaryScreens[0].name) : "" // Bar orientation: "horizontal" (top edge, default) or "vertical" (left // edge). Injected into the Bar and the SurfaceManager so layout and popout // geometry share one source of truth. property string orientation: "horizontal" // Layer-shell surfaces size from anchors/implicitWidth only at map time, so // flipping orientation at runtime needs a remap: drop the bar then re-show // it a frame later to pick up the new thickness and anchored edges. property bool barRemap: true Timer { id: barRemapTimer interval: 60 onTriggered: shell.barRemap = true } Format { id: format } Theme { id: nuguTheme lowPowerMode: power.lowPowerMode() } Time { id: time } CalDav { id: caldav } Niri { id: niri } Resources { id: resources // DI (never singletons inside the service): UPower/PowerProfiles singletons // for battery health + throttling, and the existing Brightness instance. upower: UPower powerProfiles: PowerProfiles brightnessService: brightness } Notifications { id: notifications } Tray { id: tray } Clipboard { id: clipboard surfaces: surfaceManager niriService: niri } Vault { id: vault clipboardService: clipboard panelOpen: surfaceManager.popoutOpen && surfaceManager.popoutName === "vault" } Connections { target: lock function onLogicalLockedChanged() { if (lock.logicalLocked) vault.lock(); } } Launcher { id: launcher } Osd { id: osd } Media { id: media osdService: osd audioService: audio } Audio { id: audio osdService: osd } Brightness { id: brightness osdService: osd niriService: niri } Idle { id: idle } Privilege { id: privilege } Lock { id: lock theme: nuguTheme timeService: time mediaService: media notificationService: notifications powerService: power } Network { id: network } Bluetooth { id: bluetooth } Power { id: power lockService: lock niriService: niri } Screenshots { id: screenshots niriService: niri osdService: osd } SurfaceManager { id: surfaceManager niriService: niri powerService: power mediaService: media trayService: tray } Noko { id: noko } Usage { id: usage } Diagnostics { id: diagnosticsService surfaces: surfaceManager screens: Quickshell.screens niriService: niri audioService: audio networkService: network vaultService: vault nokoService: noko } Variants { model: Quickshell.screens delegate: Component { PanelWindow { required property var modelData objectName: "osdOverlaySurface" screen: modelData // primary monitor only — no value showing the OSD once per screen. visible: osd.visibleState && modelData.name === shell.primaryScreenName implicitWidth: 316 implicitHeight: osdCard.implicitHeight + 64 color: "transparent" exclusionMode: ExclusionMode.Ignore WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "nuguland-osd" WlrLayershell.keyboardFocus: WlrKeyboardFocus.None anchors { top: true right: true } // Mirrors the notification card's visual language (backdrop // alpha, radius, IconImage, IBM Plex, accent) but stays a // glance-only meter — no close/actions/body. The mask is left // empty on purpose: the OSD is non-interactive, so the surface // must pass clicks through (the inverse of the toast mask). Rectangle { id: osdCard readonly property var indicator: osd.valueIndicator(osd.currentEvent, osd.currentValue) readonly property string roleColor: osd.currentRole === "error" ? nuguTheme.error : (osd.currentRole === "warning" ? nuguTheme.warning : nuguTheme.ui.accent) readonly property bool hasBar: indicator.progressBar && indicator.progressBar.visible readonly property bool isError: osd.currentRole === "error" readonly property string resolvedIcon: Quickshell.iconPath(String(osd.iconName(osd.currentEvent, osd.currentValue)), true) anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.topMargin: 56 anchors.rightMargin: 24 anchors.leftMargin: 8 anchors.bottomMargin: 8 implicitHeight: osdRow.implicitHeight + 24 radius: 14 color: nuguTheme.withAlpha(nuguTheme.ui.backdrop, 0.92) opacity: osd.visibleState ? 1 : 0 // left accent strip, like the notification card's urgency bar Rectangle { anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom width: 3 radius: 2 color: osdCard.roleColor } Row { id: osdRow anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: 14 anchors.rightMargin: 14 anchors.verticalCenter: parent.verticalCenter spacing: 12 Rectangle { anchors.verticalCenter: parent.verticalCenter width: 40 height: 40 radius: 12 color: nuguTheme.withAlpha(osdCard.roleColor, 0.18) IconImage { anchors.centerIn: parent width: 24 height: 24 source: osdCard.resolvedIcon visible: source.toString().length > 0 } } Column { width: parent.width - 40 - parent.spacing anchors.verticalCenter: parent.verticalCenter spacing: 7 Row { width: parent.width spacing: 8 Text { id: osdLabel color: nuguTheme.content.normal font.family: "IBM Plex Sans" font.pixelSize: 14 font.bold: true text: String(osdCard.indicator.displayLabel || "OSD") width: parent.width - osdValue.width - parent.spacing elide: Text.ElideRight } Text { id: osdValue anchors.baseline: osdLabel.baseline color: osdCard.hasBar ? osdCard.roleColor : nuguTheme.ui.normal font.family: "IBM Plex Mono" font.pixelSize: osdCard.hasBar ? 14 : 13 font.bold: osdCard.hasBar text: osdCard.isError ? "" : String(osdCard.indicator.displayValue || "") } } // hero meter for volume/brightness/microphone levels Rectangle { width: parent.width height: osdCard.hasBar ? 5 : 0 visible: osdCard.hasBar radius: 2.5 color: nuguTheme.withAlpha(nuguTheme.ui.minor, 0.28) Rectangle { anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom width: parent.width * Math.max(0, Math.min(1, osdCard.indicator.normalizedValue || 0)) radius: parent.radius color: osdCard.roleColor Behavior on width { NumberAnimation { duration: nuguTheme.lowPowerMode ? 0 : 160 easing.type: Easing.OutCubic } } } } // error payload reads in the body line Text { visible: osdCard.isError color: nuguTheme.error font.family: "IBM Plex Sans" font.pixelSize: 12 text: osd.currentValue width: parent.width wrapMode: Text.WordWrap maximumLineCount: 2 elide: Text.ElideRight } } } Behavior on opacity { NumberAnimation { duration: nuguTheme.lowPowerMode ? 0 : 120 easing.type: Easing.OutCubic } } } mask: Region {} } } } Variants { model: Quickshell.screens delegate: Component { PanelWindow { id: nokoOverlayWindow required property var modelData objectName: "nokoFocusOverlaySurface" screen: modelData visible: (noko.overlayState || "").length > 0 && String(modelData.name || "") === String(niri.focusedOutputName || shell.primaryScreenName) implicitWidth: 1 implicitHeight: 1 color: "transparent" exclusionMode: ExclusionMode.Ignore WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "nuguland-noko-overlay" WlrLayershell.keyboardFocus: WlrKeyboardFocus.None anchors { top: true left: true right: true bottom: true } NokoFocusOverlay { anchors.fill: parent theme: nuguTheme nokoService: noko niriService: niri barHeight: nokoOverlayWindow.modelData.name === shell.primaryScreenName ? surfaceManager.barHeight : 0 orientation: shell.orientation } mask: Region {} } } } Variants { model: Quickshell.screens delegate: Component { PanelWindow { id: toastSurface required property var modelData readonly property var toasts: notifications.activeToastRows() objectName: "notificationToastSurface" screen: modelData // primary monitor only, so a toast shows once, not once per screen. visible: toastSurface.toasts.length > 0 && modelData.name === shell.primaryScreenName implicitWidth: 404 implicitHeight: Math.max(1, toastColumn.implicitHeight + 64) color: "transparent" exclusionMode: ExclusionMode.Ignore WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "nuguland-toast" WlrLayershell.keyboardFocus: WlrKeyboardFocus.None anchors { top: true right: true } Column { id: toastColumn anchors.top: parent.top anchors.right: parent.right anchors.topMargin: 56 anchors.rightMargin: 24 anchors.leftMargin: 8 anchors.bottomMargin: 8 width: parent.width - 32 spacing: 8 Repeater { model: toastSurface.toasts // Wrap in a plain Item: Qt6 does NOT inject an array // model's modelData into a required property on an // external-component (NotificationCard) delegate root — // the wrapper takes the injection and passes it down // explicitly. (Same fix used for the popup in Task 3.) delegate: Item { id: toastWrap required property var modelData width: toastColumn.width implicitHeight: toastCard.implicitHeight height: implicitHeight NotificationCard { id: toastCard width: parent.width theme: nuguTheme modelData: toastWrap.modelData compact: true onDismiss: id => notifications.dismissToast(id) onInvokeAction: (id, actionId) => notifications.runAction(id, actionId) } // Dismiss + drain derive from the service-stamped // absolute expiresAt, not a fresh interval, so a // Repeater rebuild (any other toast added/removed) // resumes the countdown rather than restarting it. readonly property real toastTotal: toastWrap.modelData.timeoutMs || 0 readonly property real toastExpiry: toastWrap.modelData.expiresAt || 0 readonly property real toastRemaining: Math.max(0, toastExpiry - Date.now()) readonly property int toastProgress: toastWrap.modelData.value !== undefined ? Number(toastWrap.modelData.value) : -1 readonly property bool toastHasProgress: toastProgress >= 0 // Progress toasts persist until complete (no drain // dismissal); plain toasts auto-dismiss at expiry. Timer { running: toastWrap.toastExpiry > 0 && !toastWrap.toastHasProgress interval: Math.max(1, toastWrap.toastRemaining) repeat: false onTriggered: notifications.dismissToast(String(toastWrap.modelData.id)) } // Progress complete: auto-dismiss shortly after 100%. Timer { running: toastWrap.toastHasProgress && toastWrap.toastProgress >= 100 interval: 1500 repeat: false onTriggered: notifications.dismissToast(String(toastWrap.modelData.id)) } // bottom bar: content progress when the toast carries // a value hint, otherwise the auto-dismiss drain. Rectangle { visible: toastWrap.toastHasProgress anchors.left: toastCard.left anchors.bottom: toastCard.bottom anchors.leftMargin: 12 anchors.bottomMargin: 4 height: 2 radius: 1 color: nuguTheme ? nuguTheme.ui.accent : "transparent" width: (toastCard.width - 24) * Math.max(0, Math.min(100, toastWrap.toastProgress)) / 100 Behavior on width { NumberAnimation { duration: nuguTheme && nuguTheme.lowPowerMode ? 0 : 200 } } } Rectangle { visible: toastWrap.toastExpiry > 0 && !toastWrap.toastHasProgress anchors.left: toastCard.left anchors.bottom: toastCard.bottom anchors.leftMargin: 12 anchors.bottomMargin: 4 height: 2 radius: 1 color: nuguTheme ? nuguTheme.withAlpha(nuguTheme.ui.accent, 0.55) : "transparent" width: (toastCard.width - 24) * (toastWrap.toastTotal > 0 ? toastWrap.toastRemaining / toastWrap.toastTotal : 1) NumberAnimation on width { running: toastWrap.toastExpiry > 0 && !toastWrap.toastHasProgress && !(nuguTheme && nuguTheme.lowPowerMode) to: 0 duration: Math.max(1, toastWrap.toastRemaining) } } } } } // Accept input only over the toast cards (click to dismiss); // the transparent margins stay click-through to apps below. mask: Region { item: toastColumn } } } } Variants { model: shell.primaryScreens delegate: Component { PanelWindow { required property var modelData objectName: "privilegeSecuritySurface" screen: modelData visible: privilege.active || privilege.error.length > 0 || privilege.confirming color: "transparent" exclusionMode: ExclusionMode.Ignore WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.namespace: "nuguland-privilege" WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive anchors { top: true bottom: true left: true right: true } onVisibleChanged: if (visible) Qt.callLater(privilegeSurface.focusSecret) PrivilegeSurface { id: privilegeSurface anchors.fill: parent theme: nuguTheme privilegeService: privilege } } } } Variants { model: Quickshell.screens delegate: Component { AuroraBackdrop { required property var modelData screen: modelData resourceService: resources lowPowerMode: power.lowPowerMode() } } } Variants { model: shell.barRemap ? shell.primaryScreens : [] delegate: Component { Bar { required property var modelData // primary monitor only; the bar consolidates every output's // workspaces into per-output trays (see Bar.qml workspaceStrip). screen: modelData theme: nuguTheme niriService: niri timeService: time resourceService: resources notificationService: notifications trayService: tray mediaService: media clipboardService: clipboard vaultService: vault launcherService: launcher audioService: audio brightnessService: brightness networkService: network bluetoothService: bluetooth powerService: power privilegeService: privilege idleService: idle lockService: lock nokoService: noko surfaces: surfaceManager usageService: usage caldavService: caldav formatService: format orientation: shell.orientation } } } IpcHandler { target: "noko" function state(): string { return noko.stateJson(); } function refresh(): string { return noko.refresh(); } function install(): string { return noko.install(); } function update(): string { return noko.update(); } function checkUpdates(): string { return noko.checkUpdates(); } function trigger(): string { return noko.trigger(); } function start(): string { return noko.startCapture(); } function stop(): string { return noko.stopCapture(); } function transcribe(seconds: int): string { return noko.transcribe(seconds); } function listening(): string { return noko.beginListening(); } function transcribing(): string { return noko.beginTranscribing(); } function finish(): string { return noko.finish(); } } IpcHandler { function increase() { return audio.increase(); } function decrease() { return audio.decrease(); } function muteOutput() { return audio.muteOutput(); } function muteInput() { return audio.muteInput(); } function route(action: string): string { return audio.route(action); } target: "volume" } IpcHandler { function next() { return media.action("next"); } function previous() { return media.action("previous"); } function playPause() { return media.action("playPause"); } function stop() { return media.action("stop"); } function shuffle() { return media.action("shuffle"); } function repeat() { return media.action("repeat"); } function route(action: string): string { return media.action(action); } target: "media" } IpcHandler { function increase(): string { return brightness.increase(); } function decrease(): string { return brightness.decrease(); } target: "brightness" } IpcHandler { function usageState(): string { return usage.stateJson(); } function record(name: string): string { return usage.record(name); } target: "usage" } IpcHandler { target: "caldav" function state(): string { return caldav.stateJson(); } function selfTest(): string { return caldav.selfTest(); } function refresh(): string { caldav.refresh(); return caldav.stateJson(); } } IpcHandler { target: "system" function state(): string { return resources.stateJson(); } function selfTest(): string { return resources.selfTest(); } } IpcHandler { target: "clipboard" function selfTest(): string { return clipboard.selfTest(); } } IpcHandler { target: "vault" function state(): string { return vault.stateJson(); } function open(): string { vault.prepareOpen(niri.focusedAppId); return surfaceManager.openRegisteredPopout("vault", niri.focusedOutputName); } function lock(): string { vault.lock(); return vault.stateJson(); } function sync(): string { vault.sync(); return vault.stateJson(); } } IpcHandler { function ping(): string { return "nuguland"; } function diagnostics(): string { return diagnosticsService.snapshot(); } function niriState(): string { return niri.stateJson(); } function niriSelfTest(): string { return JSON.stringify(niri.selfTest()); } function setOrientation(mode: string): string { const want = String(mode); if (want === "toggle") shell.orientation = shell.orientation === "vertical" ? "horizontal" : "vertical"; else if (want === "horizontal" || want === "vertical") shell.orientation = want; shell.barRemap = false; barRemapTimer.restart(); return shell.orientation; } function abbreviateSelfTest(): string { return JSON.stringify(format.abbreviateSelfTest()); } function reloadTheme() { nuguTheme.reload(); return nuguTheme.mode; } function screenshotScreen(path: string): string { niri.screenshotScreen(path); return path; } function windowRuleMetadata(): string { return niri.windowRuleMetadata(); } function windowCardAction(kind: string): string { return niri.windowCardAction(kind); } function openWindow(): string { return surfaceManager.openRegisteredPopout("window"); } function timeState(): string { return time.stateJson(); } function timeStateAt(iso: string): string { return time.stateAt(iso); } function timeRelative(fromIso: string, toIso: string): string { return time.relative(fromIso, toIso); } function timeCalendar(year: int, month: int, selectedDay: int): string { return time.calendar(year, month, selectedDay); } function openClock(): string { return surfaceManager.openRegisteredPopout("clock"); } function systemWidgetState(): string { return resources.systemWidgetState(); } function openSystem(): string { return surfaceManager.openRegisteredPopout("system"); } function notificationWidgetState(attention: bool, active: bool): string { return notifications.widgetState(attention, active); } function notificationsState(): string { return notifications.stateJson(); } function notificationsToggleDnd(): string { return notifications.toggleDnd(); } function notificationsAction(id: string, actionId: string): string { return notifications.runAction(id, actionId); } function notificationsReply(id: string, text: string): string { return notifications.sendReply(id, text); } function notificationsToggleGroup(appName: string): string { return notifications.toggleGroup(appName); } function notificationsDiscardAll(): string { return notifications.discardAllNotifications(); } function notificationsSelfTest(): string { return JSON.stringify(notifications.selfTest()); } function notificationsDismissToasts(): string { return notifications.dismissToasts(); } function trayWidgetState(attention: bool, active: bool): string { return tray.widgetState(attention, active); } function trayState(): string { return tray.stateJson(); } function openTray(): string { return surfaceManager.openRegisteredPopout("tray"); } function traySelectItem(id: string): string { return tray.selectItem(id); } function trayMenuExpand(id: string): string { return tray.expandSubmenu(id); } function trayMenuActivate(id: string): string { return tray.activateRow(id); } function trayMenuClose(reason: string): string { return tray.closeMenu(reason); } function launcherSearch(query: string): string { return launcher.search(query); } function launcherState(): string { return launcher.stateJson(); } function launcherSelfTest(): string { return launcher.selfTest(); } function launcherLaunchRecord(rowJson: string): string { return launcher.launchRecord(rowJson); } function launcherActivate(rowJson: string): string { return launcher.activate(rowJson); } function launcherActivateAction(rowJson: string, index: string): string { return launcher.activateAction(rowJson, Number(index)); } function launcherActivateFirst(query: string): string { return launcher.activateFirst(query); } function launcherActivateId(id: string): string { return launcher.activateId(id); } function hotkey(id: string): string { return launcher.hotkey(id); } function openLauncher(): string { return surfaceManager.openRegisteredPopout("launcher", niri.focusedOutputName); } function osdTrigger(event: string, value: string): string { return osd.trigger(event, value); } function osdState(): string { return osd.stateJson(); } function osdExpire(): string { return osd.expire(); } function clipboardState(): string { return clipboard.stateJson(); } function clipboardSearch(query: string): string { return clipboard.search(query); } function clipboardTogglePin(id: string): string { return clipboard.togglePin(id); } function clipboardCopy(id: string): string { return clipboard.copy(id); } function clipboardPaste(id: string): string { return clipboard.paste(id); } function clipboardDelete(id: string): string { return clipboard.deleteRow(id); } function clipboardPrivateMode(enabled: bool): string { return clipboard.setPrivateMode(enabled); } function openClipboard(): string { return surfaceManager.openRegisteredPopout("clipboard"); } function openVault(): string { vault.prepareOpen(niri.focusedAppId); return surfaceManager.openRegisteredPopout("vault", niri.focusedOutputName); } function mediaState(): string { return media.stateJson(); } function openMedia(): string { return surfaceManager.openRegisteredPopout("media"); } function mediaAction(kind: string): string { return media.action(kind); } function mediaSeek(position: real): string { return media.seek(position); } function mediaSelect(id: string): string { return media.select(id); } function audioState(): string { return audio.stateJson(); } function audioSelfTest(): string { return audio.selfTest(); } function openAudio(): string { return surfaceManager.openRegisteredPopout("audio"); } function privacyWidgetState(): string { return audio.privacyWidgetJson(); } function audioSetVolume(id: string, volume: real): string { return audio.setVolume(id, volume); } function audioToggleMute(id: string): string { return audio.toggleMute(id); } function audioSetDefaultSink(id: string): string { return audio.setDefaultSink(id); } function audioSetDefaultSource(id: string): string { return audio.setDefaultSource(id); } function audioMoveStream(id: string, target: string): string { return audio.moveStream(id, target); } function brightnessState(): string { return brightness.stateJson(); } function brightnessSelfTest(): string { return brightness.selfTest(); } function openBrightness(): string { return surfaceManager.openRegisteredPopout("brightness"); } function brightnessSetLevel(level: string): string { return brightness.setLevel(level); } function brightnessIncrease(): string { return brightness.increase(); } function brightnessDecrease(): string { return brightness.decrease(); } function idleState(): string { return idle.stateJson(); } function idleToggle(): string { return idle.toggle(); } function idleDisable(): string { return idle.disable(); } function privilegeState(): string { return privilege.stateJson(); } function privilegeSubmit(secret: string): string { return privilege.submit(secret); } function privilegeDeny(): string { return privilege.deny(); } function privilegeCancel(): string { return privilege.cancel(); } function privilegeFail(message: string): string { return privilege.fail(message); } function privilegeClear(): string { return privilege.clear(); } function lockState(): string { return lock.stateJson(); } function lockRequest(): string { return lock.request(); } function lockType(secret: string): string { return lock.typeSecret(secret); } function lockSubmit(secret: string): string { return lock.submit(secret); } function lockCancel(): string { return lock.cancel(); } function networkState(): string { return network.stateJson(); } function networkSelfTest(): string { return network.selfTest(); } function networkWidgetState(): string { const state = JSON.parse(network.stateJson()); state.barLabel = "network"; state.shader.values = [resources.networkRxLevel(), resources.networkTxLevel(), state.compact.signal / 100, state.wifi.enabled ? 1 : 0]; state.shader.history = resources.shaderHistoryObject(resources.networkHistorySamples); state.rates = { "rxRate": resources.networkRxRate, "txRate": resources.networkTxRate, "rxLevel": resources.networkRxLevel(), "txLevel": resources.networkTxLevel() }; return JSON.stringify(state); } function networkScan() { return network.scan(); } function networkSelect(id: string): string { return network.select(id); } function networkToggleWifi(enabled: bool): string { return network.toggleWifi(enabled); } function networkForget(id: string): string { return network.forget(id); } function networkCheckConnectivity() { return network.checkConnectivity(); } function bluetoothState(): string { return bluetooth.stateJson(); } function bluetoothScan(): string { return bluetooth.scan(); } function bluetoothToggle(enabled: bool): string { return bluetooth.toggle(enabled); } function bluetoothDeviceAction(kind: string, id: string): string { return bluetooth.deviceAction(kind, id); } function powerState(): string { return power.stateJson(); } function openPower(): string { return surfaceManager.openRegisteredPopout("power"); } function openNetwork(): string { return surfaceManager.openRegisteredPopout("connectivity"); } function powerSelfTest(): string { return power.selfTest(); } function powerSessionAction(kind: string): string { return power.sessionAction(kind); } function powerConfirmAction(kind: string): string { return power.confirmAction(kind); } function powerCancelAction(): string { return power.cancelAction(); } function screenshotsState(): string { return screenshots.stateJson(); } function screenshotsBeginSelection(x: real, y: real): string { return screenshots.beginSelection(x, y); } function screenshotsUpdateSelection(x: real, y: real): string { return screenshots.updateSelection(x, y); } function screenshotsCompleteSelection(path: string): string { return screenshots.completeSelection(path); } function screenshotsCancelSelection(): string { return screenshots.cancelSelection(); } function screenshotsCapture(kind: string, path: string): string { return screenshots.capture(kind, path); } function screenshotsPickColor(): string { return screenshots.pickColor(); } function screenshotsRecordAction(kind: string, id: string): string { return screenshots.recordAction(kind, id); } function screenshotsClear(): string { return screenshots.clear(); } function openScreenshots(): string { return surfaceManager.openRegisteredPopout("screenshots"); } function registeredAnchors(): string { return surfaceManager.registeredAnchors(); } function popoutContentCatalog(): string { return surfaceManager.popoutContentCatalog(); } function setPopoutScreen(width: int, height: int): string { return surfaceManager.setPopoutScreen(width, height); } function openPopout(name: string, anchor: string): string { return surfaceManager.openPopout(name, anchor); } function openRegisteredPopout(name: string): string { return surfaceManager.openRegisteredPopout(name); } function openNotifications(): string { return surfaceManager.openRegisteredPopout("notifications"); } function hoverRegisteredPopout(name: string): string { return surfaceManager.hoverRegisteredPopout(name); } function closePopout(): string { return surfaceManager.closePopout(""); } function popoutInteraction(kind: string): string { return surfaceManager.popoutInteraction(kind); } function popoutState(): string { return surfaceManager.popoutState(); } function hideAll() { surfaceManager.closePopout("hideAll"); return "ok"; } target: "nuguland" } }