1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -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"
"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"
"github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
)
@@ -89,12 +90,14 @@ func SetCompositorDWL() {
}
type WindowGeometry struct {
X int32
Y int32
Width int32
Height int32
Output string
Scale float64
X int32
Y int32
Width int32
Height int32
Output string
Scale float64
OutputX int32
OutputY int32
}
func GetActiveWindow() (*WindowGeometry, error) {
@@ -382,6 +385,79 @@ func GetFocusedMonitor() string {
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) {
display, err := client.Connect("")
if err != nil {
@@ -509,13 +585,21 @@ func getDWLActiveWindow() (*WindowGeometry, error) {
if scale <= 0 {
scale = 1.0
}
var outputX, outputY int32
if ox, oy, ok := getOutputPosition(state.name); ok {
outputX, outputY = ox, oy
}
return &WindowGeometry{
X: state.x,
Y: state.y,
Width: state.w,
Height: state.h,
Output: state.name,
Scale: scale,
X: state.x,
Y: state.y,
Width: state.w,
Height: state.h,
Output: state.name,
Scale: scale,
OutputX: outputX,
OutputY: outputY,
}, nil
}

View File

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