mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
screenshot: add window capture for Hyprland
This commit is contained in:
69
core/internal/screenshot/compositor.go
Normal file
69
core/internal/screenshot/compositor.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package screenshot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type Compositor int
|
||||
|
||||
const (
|
||||
CompositorUnknown Compositor = iota
|
||||
CompositorHyprland
|
||||
)
|
||||
|
||||
func DetectCompositor() Compositor {
|
||||
if os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") != "" {
|
||||
return CompositorHyprland
|
||||
}
|
||||
return CompositorUnknown
|
||||
}
|
||||
|
||||
type WindowGeometry struct {
|
||||
X int32
|
||||
Y int32
|
||||
Width int32
|
||||
Height int32
|
||||
}
|
||||
|
||||
func GetActiveWindow() (*WindowGeometry, error) {
|
||||
compositor := DetectCompositor()
|
||||
|
||||
switch compositor {
|
||||
case CompositorHyprland:
|
||||
return getHyprlandActiveWindow()
|
||||
default:
|
||||
return nil, fmt.Errorf("window capture requires Hyprland (other compositors not yet supported)")
|
||||
}
|
||||
}
|
||||
|
||||
type hyprlandWindow struct {
|
||||
At [2]int32 `json:"at"`
|
||||
Size [2]int32 `json:"size"`
|
||||
}
|
||||
|
||||
func getHyprlandActiveWindow() (*WindowGeometry, error) {
|
||||
cmd := exec.Command("hyprctl", "-j", "activewindow")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("hyprctl activewindow: %w", err)
|
||||
}
|
||||
|
||||
var win hyprlandWindow
|
||||
if err := json.Unmarshal(output, &win); err != nil {
|
||||
return nil, fmt.Errorf("parse activewindow: %w", err)
|
||||
}
|
||||
|
||||
if win.Size[0] <= 0 || win.Size[1] <= 0 {
|
||||
return nil, fmt.Errorf("no active window")
|
||||
}
|
||||
|
||||
return &WindowGeometry{
|
||||
X: win.At[0],
|
||||
Y: win.At[1],
|
||||
Width: win.Size[0],
|
||||
Height: win.Size[1],
|
||||
}, nil
|
||||
}
|
||||
@@ -77,6 +77,8 @@ func (s *Screenshoter) Run() (*CaptureResult, error) {
|
||||
return s.captureLastRegion()
|
||||
case ModeRegion:
|
||||
return s.captureRegion()
|
||||
case ModeWindow:
|
||||
return s.captureWindow()
|
||||
case ModeOutput:
|
||||
return s.captureOutput(s.config.OutputName)
|
||||
case ModeFullScreen:
|
||||
@@ -119,6 +121,27 @@ func (s *Screenshoter) captureRegion() (*CaptureResult, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Screenshoter) captureWindow() (*CaptureResult, error) {
|
||||
geom, err := GetActiveWindow()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
region := Region{
|
||||
X: geom.X,
|
||||
Y: geom.Y,
|
||||
Width: geom.Width,
|
||||
Height: geom.Height,
|
||||
}
|
||||
|
||||
output := s.findOutputForRegion(region)
|
||||
if output == nil {
|
||||
return nil, fmt.Errorf("could not find output for window")
|
||||
}
|
||||
|
||||
return s.captureRegionOnOutput(output, region)
|
||||
}
|
||||
|
||||
func (s *Screenshoter) captureFullScreen() (*CaptureResult, error) {
|
||||
output := s.findFocusedOutput()
|
||||
if output == nil {
|
||||
|
||||
Reference in New Issue
Block a user