1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

screenshot: fix some region mappings

This commit is contained in:
bbedward
2025-12-05 15:25:27 -05:00
parent 6d0c56554f
commit 52d5e21fc4
4 changed files with 113 additions and 38 deletions

View File

@@ -14,8 +14,9 @@ import (
) )
type SelectionState struct { type SelectionState struct {
hasSelection bool // There's a selection to display (pre-loaded or user-drawn) hasSelection bool // There's a selection to display (pre-loaded or user-drawn)
dragging bool // User is actively drawing a new selection dragging bool // User is actively drawing a new selection
surface *OutputSurface // Surface where selection was made
// Surface-local logical coordinates (from pointer events) // Surface-local logical coordinates (from pointer events)
anchorX float64 anchorX float64
anchorY float64 anchorY float64
@@ -88,6 +89,9 @@ type RegionSelector struct {
running bool running bool
cancelled bool cancelled bool
result Region result Region
capturedBuffer *ShmBuffer
capturedRegion Region
} }
func NewRegionSelector(s *Screenshoter) *RegionSelector { func NewRegionSelector(s *Screenshoter) *RegionSelector {
@@ -98,59 +102,72 @@ func NewRegionSelector(s *Screenshoter) *RegionSelector {
} }
} }
func (r *RegionSelector) Run() (Region, bool, error) { func (r *RegionSelector) Run() (*CaptureResult, bool, error) {
r.preSelect = GetLastRegion() r.preSelect = GetLastRegion()
if err := r.connect(); err != nil { if err := r.connect(); err != nil {
return Region{}, false, fmt.Errorf("wayland connect: %w", err) return nil, false, fmt.Errorf("wayland connect: %w", err)
} }
defer r.cleanup() defer r.cleanup()
if err := r.setupRegistry(); err != nil { if err := r.setupRegistry(); err != nil {
return Region{}, false, fmt.Errorf("registry setup: %w", err) return nil, false, fmt.Errorf("registry setup: %w", err)
} }
if err := r.roundtrip(); err != nil { if err := r.roundtrip(); err != nil {
return Region{}, false, fmt.Errorf("roundtrip after registry: %w", err) return nil, false, fmt.Errorf("roundtrip after registry: %w", err)
} }
switch { switch {
case r.screencopy == nil: case r.screencopy == nil:
return Region{}, false, fmt.Errorf("compositor does not support wlr-screencopy-unstable-v1") return nil, false, fmt.Errorf("compositor does not support wlr-screencopy-unstable-v1")
case r.layerShell == nil: case r.layerShell == nil:
return Region{}, false, fmt.Errorf("compositor does not support wlr-layer-shell-unstable-v1") return nil, false, fmt.Errorf("compositor does not support wlr-layer-shell-unstable-v1")
case r.seat == nil: case r.seat == nil:
return Region{}, false, fmt.Errorf("no seat available") return nil, false, fmt.Errorf("no seat available")
case r.compositor == nil: case r.compositor == nil:
return Region{}, false, fmt.Errorf("compositor not available") return nil, false, fmt.Errorf("compositor not available")
case r.shm == nil: case r.shm == nil:
return Region{}, false, fmt.Errorf("wl_shm not available") return nil, false, fmt.Errorf("wl_shm not available")
case len(r.outputs) == 0: case len(r.outputs) == 0:
return Region{}, false, fmt.Errorf("no outputs available") return nil, false, fmt.Errorf("no outputs available")
} }
if err := r.roundtrip(); err != nil { if err := r.roundtrip(); err != nil {
return Region{}, false, fmt.Errorf("roundtrip after protocol check: %w", err) return nil, false, fmt.Errorf("roundtrip after protocol check: %w", err)
} }
if err := r.createSurfaces(); err != nil { if err := r.createSurfaces(); err != nil {
return Region{}, false, fmt.Errorf("create surfaces: %w", err) return nil, false, fmt.Errorf("create surfaces: %w", err)
} }
_ = r.createCursor() _ = r.createCursor()
if err := r.roundtrip(); err != nil { if err := r.roundtrip(); err != nil {
return Region{}, false, fmt.Errorf("roundtrip after surfaces: %w", err) return nil, false, fmt.Errorf("roundtrip after surfaces: %w", err)
} }
r.running = true r.running = true
for r.running { for r.running {
if err := r.ctx.Dispatch(); err != nil { if err := r.ctx.Dispatch(); err != nil {
return Region{}, false, fmt.Errorf("dispatch: %w", err) return nil, false, fmt.Errorf("dispatch: %w", err)
} }
} }
return r.result, r.cancelled, nil if r.cancelled || r.capturedBuffer == nil {
return nil, r.cancelled, nil
}
yInverted := false
if r.selection.surface != nil {
yInverted = r.selection.surface.yInverted
}
return &CaptureResult{
Buffer: r.capturedBuffer,
Region: r.result, // Global coords for saving last region
YInverted: yInverted,
}, false, nil
} }
func (r *RegionSelector) connect() error { func (r *RegionSelector) connect() error {
@@ -610,6 +627,7 @@ func (r *RegionSelector) applyPreSelection(os *OutputSurface) {
r.selection.hasSelection = true r.selection.hasSelection = true
r.selection.dragging = false r.selection.dragging = false
r.selection.surface = os
r.selection.anchorX = x1 r.selection.anchorX = x1
r.selection.anchorY = y1 r.selection.anchorY = y1
r.selection.currentX = x2 r.selection.currentX = x2

View File

@@ -71,6 +71,7 @@ func (r *RegionSelector) setupPointerHandlers() {
case 1: // pressed case 1: // pressed
r.selection.hasSelection = true r.selection.hasSelection = true
r.selection.dragging = true r.selection.dragging = true
r.selection.surface = r.activeSurface // Lock to this surface
r.selection.anchorX = r.pointerX r.selection.anchorX = r.pointerX
r.selection.anchorY = r.pointerY r.selection.anchorY = r.pointerY
r.selection.currentX = r.pointerX r.selection.currentX = r.pointerX
@@ -115,12 +116,17 @@ func (r *RegionSelector) setupKeyboardHandlers() {
} }
func (r *RegionSelector) finishSelection() { func (r *RegionSelector) finishSelection() {
if r.activeSurface == nil { if r.selection.surface == nil {
r.running = false r.running = false
return return
} }
os := r.activeSurface os := r.selection.surface
srcBuf := r.getSourceBuffer(os)
if srcBuf == nil {
r.running = false
return
}
x1, y1 := r.selection.anchorX, r.selection.anchorY x1, y1 := r.selection.anchorX, r.selection.anchorY
x2, y2 := r.selection.currentX, r.selection.currentY x2, y2 := r.selection.currentX, r.selection.currentY
@@ -133,13 +139,29 @@ func (r *RegionSelector) finishSelection() {
} }
scaleX, scaleY := 1.0, 1.0 scaleX, scaleY := 1.0, 1.0
if os.logicalW > 0 && os.screenBuf != nil { if os.logicalW > 0 {
scaleX = float64(os.screenBuf.Width) / float64(os.logicalW) scaleX = float64(srcBuf.Width) / float64(os.logicalW)
scaleY = float64(os.screenBuf.Height) / float64(os.logicalH) scaleY = float64(srcBuf.Height) / float64(os.logicalH)
} }
bx1, by1 := int32(x1*scaleX), int32(y1*scaleY) bx1 := int(x1 * scaleX)
bx2, by2 := int32(x2*scaleX), int32(y2*scaleY) by1 := int(y1 * scaleY)
bx2 := int(x2 * scaleX)
by2 := int(y2 * scaleY)
// Clamp to buffer bounds
if bx1 < 0 {
bx1 = 0
}
if by1 < 0 {
by1 = 0
}
if bx2 > srcBuf.Width {
bx2 = srcBuf.Width
}
if by2 > srcBuf.Height {
by2 = srcBuf.Height
}
w, h := bx2-bx1, by2-by1 w, h := bx2-bx1, by2-by1
if w < 1 { if w < 1 {
@@ -149,11 +171,51 @@ func (r *RegionSelector) finishSelection() {
h = 1 h = 1
} }
// Create cropped buffer and copy pixels directly
cropped, err := CreateShmBuffer(w, h, w*4)
if err != nil {
r.running = false
return
}
srcData := srcBuf.Data()
dstData := cropped.Data()
for y := 0; y < h; y++ {
srcY := by1 + y
if srcY >= srcBuf.Height {
break
}
for x := 0; x < w; x++ {
srcX := bx1 + x
if srcX >= srcBuf.Width {
break
}
si := srcY*srcBuf.Stride + srcX*4
di := y*cropped.Stride + x*4
if si+3 < len(srcData) && di+3 < len(dstData) {
dstData[di+0] = srcData[si+0]
dstData[di+1] = srcData[si+1]
dstData[di+2] = srcData[si+2]
dstData[di+3] = srcData[si+3]
}
}
}
r.capturedBuffer = cropped
r.capturedRegion = Region{
X: int32(bx1),
Y: int32(by1),
Width: int32(w),
Height: int32(h),
Output: os.output.name,
}
// Also store for "last region" feature with global coords
r.result = Region{ r.result = Region{
X: bx1 + os.output.x, X: int32(bx1) + os.output.x,
Y: by1 + os.output.y, Y: int32(by1) + os.output.y,
Width: w, Width: int32(w),
Height: h, Height: int32(h),
Output: os.output.name, Output: os.output.name,
} }

View File

@@ -72,7 +72,7 @@ func (r *RegionSelector) drawOverlay(os *OutputSurface, renderBuf *ShmBuffer) {
r.drawHUD(data, stride, w, h) r.drawHUD(data, stride, w, h)
if !r.selection.hasSelection || r.activeSurface != os { if !r.selection.hasSelection || r.selection.surface != os {
return return
} }

View File

@@ -103,24 +103,19 @@ func (s *Screenshoter) captureLastRegion() (*CaptureResult, error) {
func (s *Screenshoter) captureRegion() (*CaptureResult, error) { func (s *Screenshoter) captureRegion() (*CaptureResult, error) {
selector := NewRegionSelector(s) selector := NewRegionSelector(s)
region, cancelled, err := selector.Run() result, cancelled, err := selector.Run()
if err != nil { if err != nil {
return nil, fmt.Errorf("region selection: %w", err) return nil, fmt.Errorf("region selection: %w", err)
} }
if cancelled { if cancelled || result == nil {
return nil, nil return nil, nil
} }
output := s.findOutputForRegion(region) if err := SaveLastRegion(result.Region); err != nil {
if output == nil {
return nil, fmt.Errorf("no output found for region")
}
if err := SaveLastRegion(region); err != nil {
log.Debug("failed to save last region", "err", err) log.Debug("failed to save last region", "err", err)
} }
return s.captureRegionOnOutput(output, region) return result, nil
} }
func (s *Screenshoter) captureFullScreen() (*CaptureResult, error) { func (s *Screenshoter) captureFullScreen() (*CaptureResult, error) {