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

@@ -13,6 +13,7 @@ import (
"github.com/hjbdev/patterm/internal/persist"
"github.com/hjbdev/patterm/internal/preset"
"github.com/hjbdev/patterm/internal/projectkey"
"github.com/hjbdev/patterm/internal/protocol"
"github.com/hjbdev/patterm/internal/scratchpad"
"github.com/hjbdev/patterm/internal/trust"
)
@@ -30,9 +31,17 @@ type Project struct {
Host *toolHost
savedProcess []persist.Entry
displayMu sync.Mutex
displayOwners map[string]paneDisplayOwner
lastActive time.Time
}
type paneDisplayOwner struct {
ClientID string
Size protocol.Size
}
type projectSummary struct {
Key string
Dir string
@@ -111,17 +120,18 @@ func (r *ProjectRegistry) Open(ctx context.Context, dir string) (*Project, error
go sess.runClassifier(ctx)
p := &Project{
Key: key,
Dir: abs,
Name: filepath.Base(abs),
Session: sess,
Pads: pads,
Trust: trustStore,
Persist: persistStore,
Launcher: launcher,
Host: host,
savedProcess: savedProcesses,
lastActive: time.Now(),
Key: key,
Dir: abs,
Name: filepath.Base(abs),
Session: sess,
Pads: pads,
Trust: trustStore,
Persist: persistStore,
Launcher: launcher,
Host: host,
savedProcess: savedProcesses,
displayOwners: make(map[string]paneDisplayOwner),
lastActive: time.Now(),
}
r.mu.Lock()
@@ -156,6 +166,73 @@ func (r *ProjectRegistry) DefaultProject() *Project {
return r.projects[r.defaultProjectKey]
}
func (p *Project) ClaimPaneDisplay(clientID, paneID string, size protocol.Size) (protocol.Size, bool) {
if p == nil || paneID == "" {
return size, true
}
if size.Cols == 0 || size.Rows == 0 {
size = protocol.Size{Cols: 80, Rows: 24}
}
p.displayMu.Lock()
if p.displayOwners == nil {
p.displayOwners = make(map[string]paneDisplayOwner)
}
owner, ok := p.displayOwners[paneID]
if !ok || owner.ClientID == "" || owner.ClientID == clientID {
p.displayOwners[paneID] = paneDisplayOwner{ClientID: clientID, Size: size}
p.displayMu.Unlock()
p.Session.ResizeChild(paneID, size.Cols, size.Rows)
return size, true
}
p.displayMu.Unlock()
return owner.Size, false
}
func (p *Project) ResizeClientDisplays(clientID string, size protocol.Size) {
if p == nil || size.Cols == 0 || size.Rows == 0 {
return
}
p.displayMu.Lock()
var panes []string
for paneID, owner := range p.displayOwners {
if owner.ClientID != clientID {
continue
}
owner.Size = size
p.displayOwners[paneID] = owner
panes = append(panes, paneID)
}
p.displayMu.Unlock()
for _, paneID := range panes {
p.Session.ResizeChild(paneID, size.Cols, size.Rows)
}
p.Launcher.SetSize(size.Cols, size.Rows)
p.Host.SetSize(size.Cols, size.Rows)
}
func (p *Project) ReleaseClientDisplays(clientID string) {
if p == nil {
return
}
p.displayMu.Lock()
for paneID, owner := range p.displayOwners {
if owner.ClientID == clientID {
delete(p.displayOwners, paneID)
}
}
p.displayMu.Unlock()
}
func (p *Project) PaneDisplay(paneID string) (protocol.Size, string, bool) {
if p == nil || paneID == "" {
return protocol.Size{}, "", false
}
p.displayMu.Lock()
defer p.displayMu.Unlock()
owner, ok := p.displayOwners[paneID]
return owner.Size, owner.ClientID, ok
}
func (r *ProjectRegistry) Shutdown() {
r.mu.Lock()
projects := make([]*Project, 0, len(r.projects))