117 lines
3.0 KiB
Go
117 lines
3.0 KiB
Go
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
|
|
}
|