workspace_stack_lifecycle.go RawHistoryFolder
1// workspace_stack_lifecycle.go - Stack pane lifecycle coordination without SafeWidget wrappers
2package browser
3
4import (
5 "errors"
6 "fmt"
7 "log"
8)
9
10// StackLifecycleManager manages the lifecycle hooks around stacked pane operations.
11type StackLifecycleManager struct {
12 wm *WorkspaceManager
13 treeValidator *TreeValidator
14}
15
16// NewStackLifecycleManager creates a new stack lifecycle manager.
17func NewStackLifecycleManager(wm *WorkspaceManager, treeValidator *TreeValidator) *StackLifecycleManager {
18 return &StackLifecycleManager{
19 wm: wm,
20 treeValidator: treeValidator,
21 }
22}
23
24// CloseStackedPaneWithLifecycle validates the stack state and delegates the actual
25// close operation to the stacked pane manager. This keeps widget handling simple
26// (raw GTK pointers) while still giving us a single place for additional safety checks.
27func (slm *StackLifecycleManager) CloseStackedPaneWithLifecycle(node *paneNode) error {
28 if node == nil {
29 return errors.New("node is nil")
30 }
31
32 stackNode := node.parent
33 if stackNode == nil || !stackNode.isStacked {
34 return errors.New("node is not part of a stacked pane")
35 }
36
37 log.Printf("[stack-lifecycle] Closing stacked pane: node=%p stack=%p stackSize=%d",
38 node, stackNode, len(stackNode.stackedPanes))
39
40 if err := slm.validateStackState(stackNode, "before close"); err != nil {
41 return fmt.Errorf("invalid stack state before close: %w", err)
42 }
43
44 if slm.wm == nil || slm.wm.stackedPaneManager == nil {
45 return errors.New("stacked pane manager not available")
46 }
47
48 if err := slm.wm.stackedPaneManager.CloseStackedPane(node); err != nil {
49 return err
50 }
51
52 if slm.treeValidator != nil {
53 if err := slm.treeValidator.ValidateTree(slm.wm.root, "after stack close"); err != nil {
54 log.Printf("[stack-lifecycle] Tree validation failed after stack close: %v", err)
55 }
56 }
57
58 return nil
59}
60
61// validateStackState validates the current state of a stack before we perform operations.
62func (slm *StackLifecycleManager) validateStackState(stackNode *paneNode, operation string) error {
63 if stackNode == nil {
64 return errors.New("stack node is nil")
65 }
66
67 if !stackNode.isStacked {
68 return errors.New("node is not marked as stacked")
69 }
70
71 if len(stackNode.stackedPanes) == 0 {
72 return errors.New("stack has no panes")
73 }
74
75 if stackNode.activeStackIndex < 0 || stackNode.activeStackIndex >= len(stackNode.stackedPanes) {
76 return fmt.Errorf("invalid active stack index: %d (size: %d)",
77 stackNode.activeStackIndex, len(stackNode.stackedPanes))
78 }
79
80 for i, pane := range stackNode.stackedPanes {
81 if pane == nil {
82 return fmt.Errorf("stacked pane at index %d is nil", i)
83 }
84 if pane.parent != stackNode {
85 return fmt.Errorf("stacked pane at index %d has wrong parent", i)
86 }
87 }
88
89 log.Printf("[stack-lifecycle] Stack state valid for operation '%s': size=%d activeIndex=%d",
90 operation, len(stackNode.stackedPanes), stackNode.activeStackIndex)
91 return nil
92}