From 7c2d5ce15ee75bfd73d4eff4679c51220db37d06 Mon Sep 17 00:00:00 2001 From: purian23 Date: Fri, 29 May 2026 17:03:19 -0400 Subject: [PATCH] fix(Screenshot): allow region capture over shell overlays --- core/cmd/dms/commands_screenshot.go | 36 +++++++++++++++++-- quickshell/Common/ModalManager.qml | 1 + quickshell/Common/PopoutManager.qml | 5 +++ quickshell/DMSShellIPC.qml | 15 ++++++++ .../DankLauncherV2ModalConnected.qml | 2 +- .../DankLauncherV2ModalSpotlight.qml | 2 +- .../DankLauncherV2ModalStandalone.qml | 2 +- .../DankLauncherV2/LauncherContextMenu.qml | 2 +- .../ControlCenter/Components/EditControls.qml | 2 +- .../Modules/DankBar/Widgets/SystemTrayBar.qml | 4 +++ .../Modules/Plugins/DesktopPluginWrapper.qml | 2 ++ .../WorkspaceOverlays/HyprlandOverview.qml | 2 ++ .../WorkspaceOverlays/NiriOverviewOverlay.qml | 2 ++ quickshell/Widgets/DankPopoutConnected.qml | 2 ++ quickshell/Widgets/DankPopoutStandalone.qml | 2 ++ 15 files changed, 74 insertions(+), 7 deletions(-) diff --git a/core/cmd/dms/commands_screenshot.go b/core/cmd/dms/commands_screenshot.go index 28750194..909b6ded 100644 --- a/core/cmd/dms/commands_screenshot.go +++ b/core/cmd/dms/commands_screenshot.go @@ -4,7 +4,9 @@ import ( "bytes" "fmt" "os" + "os/exec" "path/filepath" + "strconv" "strings" "github.com/AvengeMedia/DankMaterialShell/core/internal/clipboard" @@ -179,9 +181,39 @@ func getScreenshotConfig(mode screenshot.Mode) screenshot.Config { return config } +// setPopoutScreenshotMode toggles the shell handshake so popouts drop their keyboard grab during region select. Best-effort. +func setPopoutScreenshotMode(begin bool) { + fn := "end" + if begin { + fn = "begin" + } + cmdArgs := []string{"ipc"} + if pid, ok := getFirstDMSPID(); ok { + cmdArgs = append(cmdArgs, "--pid", strconv.Itoa(pid)) + } else { + if err := findConfig(nil, nil); err != nil { + return + } + if qsHasAnyDisplay() { + cmdArgs = append(cmdArgs, "--any-display") + } + cmdArgs = append(cmdArgs, "-p", configPath) + } + cmdArgs = append(cmdArgs, "call", "screenshot", fn) + _ = exec.Command("qs", cmdArgs...).Run() +} + func runScreenshot(config screenshot.Config) { - sc := screenshot.New(config) - result, err := sc.Run() + // Region select needs the keyboard; drop popout grabs for its duration. + result, err := func() (*screenshot.CaptureResult, error) { + interactive := config.Mode == screenshot.ModeRegion || config.Mode == screenshot.ModeLastRegion + if interactive { + setPopoutScreenshotMode(true) + defer setPopoutScreenshotMode(false) + } + return screenshot.New(config).Run() + }() + if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) diff --git a/quickshell/Common/ModalManager.qml b/quickshell/Common/ModalManager.qml index 75b11f79..d6f2c370 100644 --- a/quickshell/Common/ModalManager.qml +++ b/quickshell/Common/ModalManager.qml @@ -13,6 +13,7 @@ Singleton { property var currentModalsByScreen: ({}) function openModal(modal) { + PopoutManager.screenshotActive = false; const screenName = modal.effectiveScreen?.name ?? "unknown"; currentModalsByScreen[screenName] = modal; modalChanged(); diff --git a/quickshell/Common/PopoutManager.qml b/quickshell/Common/PopoutManager.qml index 47b4edad..1c4c7aa5 100644 --- a/quickshell/Common/PopoutManager.qml +++ b/quickshell/Common/PopoutManager.qml @@ -10,6 +10,9 @@ Singleton { property var currentPopoutsByScreen: ({}) property var currentPopoutTriggers: ({}) + // Set by the screenshot IPC handshake (dms screenshot region select); cleared by end() or any popout/modal open. + property bool screenshotActive: false + signal popoutOpening signal popoutChanged @@ -47,6 +50,7 @@ Singleton { function showPopout(popout) { if (!popout || !popout.screen) return; + screenshotActive = false; popoutOpening(); const screenName = popout.screen.name; @@ -97,6 +101,7 @@ Singleton { function requestPopout(popout, tabIndex, triggerSource) { if (!popout || !popout.screen) return; + screenshotActive = false; const screenName = popout.screen.name; const currentPopout = currentPopoutsByScreen[screenName]; const triggerId = triggerSource !== undefined ? triggerSource : tabIndex; diff --git a/quickshell/DMSShellIPC.qml b/quickshell/DMSShellIPC.qml index 83567d07..f26544af 100644 --- a/quickshell/DMSShellIPC.qml +++ b/quickshell/DMSShellIPC.qml @@ -161,6 +161,21 @@ Item { target: "control-center" } + IpcHandler { + // Screenshot region-select handshake + function begin(): string { + PopoutManager.screenshotActive = true; + return "SCREENSHOT_MODE_ON"; + } + + function end(): string { + PopoutManager.screenshotActive = false; + return "SCREENSHOT_MODE_OFF"; + } + + target: "screenshot" + } + IpcHandler { function resolveTabIndex(tab: string): int { switch ((tab || "").toLowerCase()) { diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml index d130fb8a..520e3b0e 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml @@ -689,7 +689,7 @@ Item { WlrLayershell.namespace: "dms:spotlight" WlrLayershell.layer: root.effectiveLauncherLayer WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None + WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None) anchors { left: true diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml index f17e3cba..75bee252 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalSpotlight.qml @@ -345,7 +345,7 @@ Item { WlrLayershell.namespace: "dms:spotlight" WlrLayershell.layer: root.effectiveLauncherLayer WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None + WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None) anchors { top: true diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml index 4d9222a2..55901d7a 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalStandalone.qml @@ -381,7 +381,7 @@ Item { WlrLayershell.namespace: "dms:spotlight" WlrLayershell.layer: root.effectiveLauncherLayer WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None + WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (keyboardActive ? (root.useHyprlandFocusGrab ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.Exclusive) : WlrKeyboardFocus.None) anchors { top: true diff --git a/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml b/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml index 0056ac6c..f20dede8 100644 --- a/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml +++ b/quickshell/Modals/DankLauncherV2/LauncherContextMenu.qml @@ -446,7 +446,7 @@ Item { WlrLayershell.namespace: "dms:launcher-context-menu" WlrLayershell.layer: WlrLayershell.Overlay WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: root.renderActive ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (root.renderActive ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None) anchors { top: true diff --git a/quickshell/Modules/ControlCenter/Components/EditControls.qml b/quickshell/Modules/ControlCenter/Components/EditControls.qml index e8534c62..8a5ae712 100644 --- a/quickshell/Modules/ControlCenter/Components/EditControls.qml +++ b/quickshell/Modules/ControlCenter/Components/EditControls.qml @@ -50,7 +50,7 @@ Row { WlrLayershell.namespace: "dms:control-center-widget-library" WlrLayershell.layer: WlrLayershell.Overlay WlrLayershell.exclusiveZone: -1 - WlrLayershell.keyboardFocus: visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None + WlrLayershell.keyboardFocus: PopoutManager.screenshotActive ? WlrKeyboardFocus.None : (visible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None) anchors { top: true diff --git a/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml b/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml index ffb8d55e..78853995 100644 --- a/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml +++ b/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml @@ -981,6 +981,8 @@ BasePill { WlrLayershell.layer: root.barUsesOverlayLayer ? WlrLayershell.Overlay : WlrLayershell.Top WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (!root.menuOpen) return WlrKeyboardFocus.None; if (CompositorService.useHyprlandFocusGrab) @@ -1449,6 +1451,8 @@ BasePill { WlrLayershell.layer: root.barUsesOverlayLayer ? WlrLayershell.Overlay : WlrLayershell.Top WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (!menuRoot.showMenu) return WlrKeyboardFocus.None; if (CompositorService.useHyprlandFocusGrab) diff --git a/quickshell/Modules/Plugins/DesktopPluginWrapper.qml b/quickshell/Modules/Plugins/DesktopPluginWrapper.qml index 8a8619ee..7ddf16e5 100644 --- a/quickshell/Modules/Plugins/DesktopPluginWrapper.qml +++ b/quickshell/Modules/Plugins/DesktopPluginWrapper.qml @@ -300,6 +300,8 @@ Item { } WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (root.isInteracting) { if (CompositorService.useHyprlandFocusGrab) return WlrKeyboardFocus.OnDemand; diff --git a/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml b/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml index 81af3866..d0a7a53c 100644 --- a/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml +++ b/quickshell/Modules/WorkspaceOverlays/HyprlandOverview.qml @@ -34,6 +34,8 @@ Scope { WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (!overviewScope.overviewOpen) return WlrKeyboardFocus.None; if (CompositorService.useHyprlandFocusGrab) diff --git a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml index b3e4070d..03cb5413 100644 --- a/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml +++ b/quickshell/Modules/WorkspaceOverlays/NiriOverviewOverlay.qml @@ -124,6 +124,8 @@ Scope { WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (!NiriService.inOverview) return WlrKeyboardFocus.None; if (!isActiveScreen) diff --git a/quickshell/Widgets/DankPopoutConnected.qml b/quickshell/Widgets/DankPopoutConnected.qml index 4c6630e3..24f81372 100644 --- a/quickshell/Widgets/DankPopoutConnected.qml +++ b/quickshell/Widgets/DankPopoutConnected.qml @@ -749,6 +749,8 @@ Item { WlrLayershell.layer: root.effectivePopoutLayer WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (customKeyboardFocus !== null) return customKeyboardFocus; if (!shouldBeVisible) diff --git a/quickshell/Widgets/DankPopoutStandalone.qml b/quickshell/Widgets/DankPopoutStandalone.qml index 3f7e32a4..dfd20198 100644 --- a/quickshell/Widgets/DankPopoutStandalone.qml +++ b/quickshell/Widgets/DankPopoutStandalone.qml @@ -620,6 +620,8 @@ Item { WlrLayershell.layer: root.effectivePopoutLayer WlrLayershell.exclusiveZone: -1 WlrLayershell.keyboardFocus: { + if (PopoutManager.screenshotActive) + return WlrKeyboardFocus.None; if (customKeyboardFocus !== null) return customKeyboardFocus; if (!shouldBeVisible)