winch_unix.go

 1//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || aix || zos
 2// +build darwin dragonfly freebsd linux netbsd openbsd solaris aix zos
 3
 4package uv
 5
 6import (
 7	"context"
 8	"os"
 9	"os/signal"
10	"sync"
11	"syscall"
12
13	"github.com/charmbracelet/x/term"
14	"github.com/charmbracelet/x/termios"
15)
16
17func (l *WinChReceiver) receiveEvents(ctx context.Context, f term.File, evch chan<- Event) error {
18	sig := make(chan os.Signal, 1)
19	signal.Notify(sig, syscall.SIGWINCH)
20
21	sendWinSize := func(w, h int) {
22		select {
23		case <-ctx.Done():
24		case evch <- WindowSizeEvent{w, h}:
25		}
26	}
27
28	sendPixelSize := func(w, h int) {
29		select {
30		case <-ctx.Done():
31		case evch <- WindowPixelSizeEvent{w, h}:
32		}
33	}
34
35	defer signal.Stop(sig)
36
37	// Send the initial window size.
38	winsize, err := termios.GetWinsize(int(f.Fd()))
39	if err != nil {
40		return err
41	}
42
43	var wg sync.WaitGroup
44	wg.Add(1)
45	go func() {
46		defer wg.Done()
47		sendWinSize(int(winsize.Col), int(winsize.Row))
48	}()
49
50	wg.Add(1)
51	go func() {
52		defer wg.Done()
53		sendPixelSize(int(winsize.Xpixel), int(winsize.Ypixel))
54	}()
55
56	// Wait for all goroutines to finish before continuing.
57	wg.Wait()
58
59	// Listen for window size changes.
60	for {
61		select {
62		case <-ctx.Done():
63			return nil
64		case <-sig:
65			winsize, err := termios.GetWinsize(int(f.Fd()))
66			if err != nil {
67				return err
68			}
69
70			wg.Add(1)
71			go func() {
72				defer wg.Done()
73				sendWinSize(int(winsize.Col), int(winsize.Row))
74			}()
75
76			wg.Add(1)
77			go func() {
78				defer wg.Done()
79				sendPixelSize(int(winsize.Xpixel), int(winsize.Ypixel))
80			}()
81
82			// Wait for all goroutines to finish before continuing.
83			wg.Wait()
84		}
85	}
86}