add per-pane display ownership

This commit is contained in:
2026-05-27 14:30:47 +01:00
parent 63cb8a4388
commit 6d15626e05
9 changed files with 333 additions and 36 deletions

View File

@@ -294,14 +294,9 @@ func handleDaemonAttach(ctx context.Context, registry *ProjectRegistry, t protoc
_ = sendProtocolError(t, "no project open")
return
}
if attach.TermSize.Cols > 0 && attach.TermSize.Rows > 0 {
project.Session.ResizeAll(attach.TermSize.Cols, attach.TermSize.Rows)
project.Launcher.SetSize(attach.TermSize.Cols, attach.TermSize.Rows)
project.Host.SetSize(attach.TermSize.Cols, attach.TermSize.Rows)
}
clientID := fmt.Sprintf("c-%d", time.Now().UnixNano())
view := ClientView{
ID: fmt.Sprintf("c-%d", time.Now().UnixNano()),
ID: clientID,
ProjectKey: project.Key,
ProjectName: project.Name,
Cols: attach.TermSize.Cols,
@@ -309,16 +304,18 @@ func handleDaemonAttach(ctx context.Context, registry *ProjectRegistry, t protoc
}
if child := firstRunningTopLevel(project.Session.Children()); child != nil {
view.FocusChild(child.ID)
project.ClaimPaneDisplay(clientID, child.ID, attach.TermSize)
}
sub := newClientSubscriber(project.Key, defaultClientSubscriberQueue)
sub := newClientSubscriber(project, clientID, defaultClientSubscriberQueue)
project.Session.SubscribeClient(sub)
defer project.Session.UnsubscribeClient(sub)
defer project.ReleaseClientDisplays(clientID)
_ = sendHello(t, project, view.ID)
_ = sendProjectList(t, registry, project.Key)
_ = sendChrome(t, project, view)
if view.FocusedID != "" {
_ = sendSnapshot(t, project, view.FocusedID)
_ = sendSnapshot(t, project, clientID, view.FocusedID)
}
// Close the transport when the daemon context is cancelled (shutdown or
@@ -361,22 +358,28 @@ func handleDaemonAttach(ctx context.Context, registry *ProjectRegistry, t protoc
case protocol.FrameResize:
msg, err := protocol.Decode[protocol.Resize](f)
if err == nil {
project.Session.ResizeAll(msg.Size.Cols, msg.Size.Rows)
project.Launcher.SetSize(msg.Size.Cols, msg.Size.Rows)
project.Host.SetSize(msg.Size.Cols, msg.Size.Rows)
view.Resize(msg.Size.Cols, msg.Size.Rows)
if view.FocusedID != "" {
if _, _, ok := project.PaneDisplay(view.FocusedID); !ok {
project.ClaimPaneDisplay(clientID, view.FocusedID, msg.Size)
}
}
project.ResizeClientDisplays(clientID, msg.Size)
}
case protocol.FrameFocus:
msg, err := protocol.Decode[protocol.Focus](f)
if err == nil && msg.PaneID != "" {
view.FocusChild(msg.PaneID)
project.ClaimPaneDisplay(clientID, msg.PaneID, protocol.Size{Cols: view.Cols, Rows: view.Rows})
_ = sendChrome(t, project, view)
_ = sendSnapshot(t, project, msg.PaneID)
_ = sendSnapshot(t, project, clientID, msg.PaneID)
}
case protocol.FramePaletteCommand:
if child := handleDaemonPaletteCommand(project, f); child != nil {
view.FocusChild(child.ID)
project.ClaimPaneDisplay(clientID, child.ID, protocol.Size{Cols: view.Cols, Rows: view.Rows})
_ = sendChrome(t, project, view)
_ = sendSnapshot(t, project, child.ID)
_ = sendSnapshot(t, project, clientID, child.ID)
}
}
select {
@@ -451,12 +454,18 @@ func sendChrome(t protocol.Transport, p *Project, view ClientView) error {
return t.Send(f)
}
func sendSnapshot(t protocol.Transport, p *Project, paneID string) error {
func sendSnapshot(t protocol.Transport, p *Project, clientID, paneID string) error {
b, err := p.Session.SerializeChild(paneID)
if err != nil {
return nil
}
f, err := protocol.NewFrame(protocol.FramePaneSnapshot, protocol.PaneSnapshot{PaneID: paneID, Bytes: b})
size, ownerID, _ := p.PaneDisplay(paneID)
f, err := protocol.NewFrame(protocol.FramePaneSnapshot, protocol.PaneSnapshot{
PaneID: paneID,
Bytes: b,
Size: size,
DisplayOwner: ownerID == "" || ownerID == clientID,
})
if err != nil {
return err
}