Files
overlord/Overlord-Client/cmd/agent/capture/cursor_stream.go
T

117 lines
3.0 KiB
Go
Raw Normal View History

2026-07-19 01:22:42 -05:00
package capture
import (
"context"
"image"
"sync"
rt "overlord-client/cmd/agent/runtime"
"overlord-client/cmd/agent/wire"
)
type DesktopCursorMetadata struct {
X int
Y int
Visible bool
Enabled bool
Shape uint64
Generation uint64
CursorWidth int
CursorHeight int
HotspotX int
HotspotY int
Image []byte
}
type desktopCursorStreamState struct {
x int
y int
width int
height int
visible bool
enabled bool
shape uint64
generation uint64
}
var desktopCursorStream struct {
sync.Mutex
last desktopCursorStreamState
}
func emitDesktopCursor(ctx context.Context, env *rt.Env, display, frameWidth, frameHeight int) {
desktopCursorStream.Lock()
previousSize := desktopCursorStream.last
desktopCursorStream.Unlock()
frameWidth, frameHeight = resolveCursorFrameSize(
frameWidth,
frameHeight,
previousSize,
DisplayBounds(display),
)
cursor := DesktopCursorState(display, frameWidth, frameHeight)
desktopCursorStream.Lock()
previous := desktopCursorStream.last
positionChanged := cursor.X != previous.x || cursor.Y != previous.y ||
frameWidth != previous.width || frameHeight != previous.height ||
cursor.Visible != previous.visible || cursor.Enabled != previous.enabled
shapeChanged := cursorShapeNeedsRefresh(cursor, previous, frameWidth, frameHeight)
includeShape := shapeChanged && len(cursor.Image) != 0
if !positionChanged && !includeShape {
desktopCursorStream.Unlock()
return
}
next := previous
next.x, next.y = cursor.X, cursor.Y
next.width, next.height = frameWidth, frameHeight
next.visible, next.enabled = cursor.Visible, cursor.Enabled
if includeShape {
next.shape, next.generation = cursor.Shape, cursor.Generation
}
desktopCursorStream.last = next
desktopCursorStream.Unlock()
if !cursor.Enabled && !previous.enabled {
return
}
message := wire.DesktopCursor{
Type: "desktop_cursor",
X: cursor.X,
Y: cursor.Y,
Width: frameWidth,
Height: frameHeight,
Visible: cursor.Enabled && cursor.Visible,
}
if includeShape {
message.CursorWidth = cursor.CursorWidth
message.CursorHeight = cursor.CursorHeight
message.HotspotX = cursor.HotspotX
message.HotspotY = cursor.HotspotY
message.Image = cursor.Image
}
_ = wire.WriteMsg(ctx, env.Conn, message)
}
func cursorShapeNeedsRefresh(cursor DesktopCursorMetadata, previous desktopCursorStreamState, frameWidth, frameHeight int) bool {
return cursor.Enabled &&
(cursor.Shape != previous.shape || cursor.Generation != previous.generation ||
frameWidth != previous.width || frameHeight != previous.height)
}
func resolveCursorFrameSize(frameWidth, frameHeight int, previous desktopCursorStreamState, captureBounds image.Rectangle) (int, int) {
if frameWidth <= 0 {
frameWidth = previous.width
if frameWidth <= 0 {
frameWidth = captureBounds.Dx()
}
}
if frameHeight <= 0 {
frameHeight = previous.height
if frameHeight <= 0 {
frameHeight = captureBounds.Dy()
}
}
return frameWidth, frameHeight
}