mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-23 07:09:08 +02:00
Attach to the X server on the active VT and keep a retryable DXGI frame from tearing down the capturer
Claude-Session: https://claude.ai/code/session_01QKDYfH4WKLbpNQHccpVo3P
This commit is contained in:
@@ -4,6 +4,7 @@ package server
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"image"
|
||||
)
|
||||
|
||||
@@ -29,17 +30,13 @@ func (s *session) pendingCursorRect(pf clientPixelFormat) []byte {
|
||||
// cannot produce one, or the sprite failed to encode. Say which, once per
|
||||
// session, so the next report of a missing cursor names its own cause.
|
||||
if !supported || failed || composite {
|
||||
s.cursorSkipOnce.Do(func() {
|
||||
s.log.Debugf("no cursor rect: client_requested=%v source_failed=%v compositing=%v",
|
||||
supported, failed, composite)
|
||||
})
|
||||
s.logCursorSkip("no cursor rect: client_requested=%v source_failed=%v compositing=%v",
|
||||
supported, failed, composite)
|
||||
return nil
|
||||
}
|
||||
src, ok := s.capturer.(cursorSource)
|
||||
if !ok {
|
||||
s.cursorSkipOnce.Do(func() {
|
||||
s.log.Debugf("no cursor rect: capturer %T reports no cursor source", s.capturer)
|
||||
})
|
||||
s.logCursorSkip("no cursor rect: capturer %T reports no cursor source", s.capturer)
|
||||
return nil
|
||||
}
|
||||
img, hotX, hotY, serial, err := src.Cursor()
|
||||
@@ -51,9 +48,7 @@ func (s *session) pendingCursorRect(pf clientPixelFormat) []byte {
|
||||
return nil
|
||||
}
|
||||
if img == nil {
|
||||
s.cursorSkipOnce.Do(func() {
|
||||
s.log.Debug("no cursor rect: capturer returned no sprite")
|
||||
})
|
||||
s.logCursorSkip("no cursor rect: capturer returned no sprite")
|
||||
return nil
|
||||
}
|
||||
if serial == lastSerial {
|
||||
@@ -61,11 +56,9 @@ func (s *session) pendingCursorRect(pf clientPixelFormat) []byte {
|
||||
}
|
||||
buf := encodeCursorPseudoRect(img, hotX, hotY, pf)
|
||||
if buf == nil {
|
||||
s.cursorSkipOnce.Do(func() {
|
||||
b := img.Bounds()
|
||||
s.log.Debugf("no cursor rect: sprite %dx%d stride=%d pix=%d could not be encoded",
|
||||
b.Dx(), b.Dy(), img.Stride, len(img.Pix))
|
||||
})
|
||||
b := img.Bounds()
|
||||
s.logCursorSkip("no cursor rect: sprite %dx%d stride=%d pix=%d could not be encoded",
|
||||
b.Dx(), b.Dy(), img.Stride, len(img.Pix))
|
||||
return nil
|
||||
}
|
||||
// Re-check under the write lock so a cursor another goroutine already
|
||||
@@ -89,6 +82,28 @@ func (s *session) pendingCursorRect(pf clientPixelFormat) []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
// logCursorSkip reports why this update carries no cursor rect, once per
|
||||
// distinct line. pendingCursorRect runs per framebuffer update, so an
|
||||
// unthrottled log would flood; throttling once per session instead would let
|
||||
// whichever reason came first hide every later one, and the reasons do change
|
||||
// as the client negotiates encodings and the cursor source starts failing.
|
||||
func (s *session) logCursorSkip(format string, args ...any) {
|
||||
msg := fmt.Sprintf(format, args...)
|
||||
|
||||
s.cursorSkipMu.Lock()
|
||||
if s.cursorSkipSeen == nil {
|
||||
s.cursorSkipSeen = make(map[string]struct{})
|
||||
}
|
||||
_, seen := s.cursorSkipSeen[msg]
|
||||
s.cursorSkipSeen[msg] = struct{}{}
|
||||
s.cursorSkipMu.Unlock()
|
||||
|
||||
if seen {
|
||||
return
|
||||
}
|
||||
s.log.Debug(msg)
|
||||
}
|
||||
|
||||
// maxCursorDim caps the cursor sprite size we'll encode. Real platform
|
||||
// cursors are tiny (<=256×256 on every supported OS); a value past this
|
||||
// almost certainly indicates a corrupted platform-API response, and
|
||||
|
||||
Reference in New Issue
Block a user