1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-30 00:12:50 -05:00

screenshot: use wlr-output-management on DWL for x/y offsets

This commit is contained in:
bbedward
2025-12-08 10:53:08 -05:00
parent 57ee0fb2bd
commit 29571fc3aa
2 changed files with 105 additions and 39 deletions

View File

@@ -7,6 +7,7 @@ import (
"os/exec" "os/exec"
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc" "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc"
"github.com/AvengeMedia/DankMaterialShell/core/internal/proto/wlr_output_management"
wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client" wlhelpers "github.com/AvengeMedia/DankMaterialShell/core/internal/wayland/client"
"github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
) )
@@ -89,12 +90,14 @@ func SetCompositorDWL() {
} }
type WindowGeometry struct { type WindowGeometry struct {
X int32 X int32
Y int32 Y int32
Width int32 Width int32
Height int32 Height int32
Output string Output string
Scale float64 Scale float64
OutputX int32
OutputY int32
} }
func GetActiveWindow() (*WindowGeometry, error) { func GetActiveWindow() (*WindowGeometry, error) {
@@ -382,6 +385,79 @@ func GetFocusedMonitor() string {
return "" return ""
} }
func getOutputPosition(outputName string) (x, y int32, ok bool) {
display, err := client.Connect("")
if err != nil {
return 0, 0, false
}
ctx := display.Context()
defer ctx.Close()
registry, err := display.GetRegistry()
if err != nil {
return 0, 0, false
}
var outputManager *wlr_output_management.ZwlrOutputManagerV1
registry.SetGlobalHandler(func(e client.RegistryGlobalEvent) {
if e.Interface == wlr_output_management.ZwlrOutputManagerV1InterfaceName {
mgr := wlr_output_management.NewZwlrOutputManagerV1(ctx)
version := e.Version
if version > 4 {
version = 4
}
if err := registry.Bind(e.Name, e.Interface, version, mgr); err == nil {
outputManager = mgr
}
}
})
if err := wlhelpers.Roundtrip(display, ctx); err != nil {
return 0, 0, false
}
if outputManager == nil {
return 0, 0, false
}
type headState struct {
name string
x, y int32
}
heads := make(map[*wlr_output_management.ZwlrOutputHeadV1]*headState)
done := false
outputManager.SetHeadHandler(func(e wlr_output_management.ZwlrOutputManagerV1HeadEvent) {
state := &headState{}
heads[e.Head] = state
e.Head.SetNameHandler(func(ne wlr_output_management.ZwlrOutputHeadV1NameEvent) {
state.name = ne.Name
})
e.Head.SetPositionHandler(func(pe wlr_output_management.ZwlrOutputHeadV1PositionEvent) {
state.x = pe.X
state.y = pe.Y
})
})
outputManager.SetDoneHandler(func(e wlr_output_management.ZwlrOutputManagerV1DoneEvent) {
done = true
})
for !done {
if err := ctx.Dispatch(); err != nil {
return 0, 0, false
}
}
for _, state := range heads {
if state.name == outputName {
return state.x, state.y, true
}
}
return 0, 0, false
}
func getDWLActiveWindow() (*WindowGeometry, error) { func getDWLActiveWindow() (*WindowGeometry, error) {
display, err := client.Connect("") display, err := client.Connect("")
if err != nil { if err != nil {
@@ -509,13 +585,21 @@ func getDWLActiveWindow() (*WindowGeometry, error) {
if scale <= 0 { if scale <= 0 {
scale = 1.0 scale = 1.0
} }
var outputX, outputY int32
if ox, oy, ok := getOutputPosition(state.name); ok {
outputX, outputY = ox, oy
}
return &WindowGeometry{ return &WindowGeometry{
X: state.x, X: state.x,
Y: state.y, Y: state.y,
Width: state.w, Width: state.w,
Height: state.h, Height: state.h,
Output: state.name, Output: state.name,
Scale: scale, Scale: scale,
OutputX: outputX,
OutputY: outputY,
}, nil }, nil
} }

View File

@@ -150,51 +150,33 @@ func (s *Screenshoter) captureWindow() (*CaptureResult, error) {
case CompositorHyprland: case CompositorHyprland:
return s.captureAndCrop(output, region) return s.captureAndCrop(output, region)
case CompositorDWL: case CompositorDWL:
return s.captureDWLWindow(output, region, geom.Scale) return s.captureDWLWindow(output, region, geom)
default: default:
return s.captureRegionOnOutput(output, region) return s.captureRegionOnOutput(output, region)
} }
} }
func (s *Screenshoter) captureDWLWindow(output *WaylandOutput, region Region, dwlScale float64) (*CaptureResult, error) { func (s *Screenshoter) captureDWLWindow(output *WaylandOutput, region Region, geom *WindowGeometry) (*CaptureResult, error) {
result, err := s.captureWholeOutput(output) result, err := s.captureWholeOutput(output)
if err != nil { if err != nil {
return nil, err return nil, err
} }
scale := dwlScale scale := geom.Scale
if scale <= 0 { if scale <= 0 || scale == 1.0 {
scale = float64(result.Buffer.Width) / float64(output.width) if output.fractionalScale > 1.0 {
scale = output.fractionalScale
}
} }
if scale <= 0 { if scale <= 0 {
scale = 1.0 scale = 1.0
} }
localX := int(float64(region.X) * scale) localX := int(float64(region.X-geom.OutputX) * scale)
localY := int(float64(region.Y) * scale) localY := int(float64(region.Y-geom.OutputY) * scale)
if localX >= result.Buffer.Width {
localX = localX % result.Buffer.Width
}
if localY >= result.Buffer.Height {
localY = localY % result.Buffer.Height
}
w := int(float64(region.Width) * scale) w := int(float64(region.Width) * scale)
h := int(float64(region.Height) * scale) h := int(float64(region.Height) * scale)
if localY+h > result.Buffer.Height && h <= result.Buffer.Height {
localY = result.Buffer.Height - h
if localY < 0 {
localY = 0
}
}
if localX+w > result.Buffer.Width && w <= result.Buffer.Width {
localX = result.Buffer.Width - w
if localX < 0 {
localX = 0
}
}
if localX < 0 { if localX < 0 {
w += localX w += localX
localX = 0 localX = 0