diff --git a/internal/zenutil/env_darwin.go b/internal/zenutil/env_darwin.go index 5b4a557..39b99f8 100644 --- a/internal/zenutil/env_darwin.go +++ b/internal/zenutil/env_darwin.go @@ -1,16 +1,7 @@ package zenutil -import "strconv" - // These are internal. var ( Separator = "\x00" LineBreak = "\n" ) - -func ParseWindowId(id string) any { - if pid, err := strconv.ParseUint(id, 0, 64); err == nil { - return int(pid) - } - return id -} diff --git a/internal/zenutil/env_unix.go b/internal/zenutil/env_unix.go index 79bbd6d..ad4003b 100644 --- a/internal/zenutil/env_unix.go +++ b/internal/zenutil/env_unix.go @@ -2,15 +2,8 @@ package zenutil -import "strconv" - // These are internal. var ( Separator = "\x1e" LineBreak = "\n" ) - -func ParseWindowId(id string) int { - wid, _ := strconv.ParseUint(id, 0, 64) - return int(wid) -} diff --git a/internal/zenutil/env_windows.go b/internal/zenutil/env_windows.go index 168e6c3..e8e1894 100644 --- a/internal/zenutil/env_windows.go +++ b/internal/zenutil/env_windows.go @@ -1,14 +1,7 @@ package zenutil -import "strconv" - // These are internal. var ( Separator string LineBreak = "\r\n" ) - -func ParseWindowId(id string) uintptr { - hwnd, _ := strconv.ParseUint(id, 0, 64) - return uintptr(hwnd) -} diff --git a/internal/zenutil/window_darwin.go b/internal/zenutil/window_darwin.go new file mode 100644 index 0000000..3bffc43 --- /dev/null +++ b/internal/zenutil/window_darwin.go @@ -0,0 +1,91 @@ +package zenutil + +import ( + "os" + "strconv" + "syscall" + "unsafe" +) + +// ParseWindowId is internal. +func ParseWindowId(id string) any { + if pid, err := strconv.ParseUint(id, 0, 64); err == nil { + return int(pid) + } + return id +} + +// GetParentWindowId is internal. +func GetParentWindowId() int { + buf, err := sysctlKernProcAll() + if err != nil { + return 0 + } + + type kinfo_proc struct { + _ [40]byte + Pid int32 + _ [516]byte + PPid int32 + _ [84]byte + } + const size = int(unsafe.Sizeof(kinfo_proc{})) + + ppids := map[int]int{} + for i := 0; i+size < len(buf); i += size { + p := (*kinfo_proc)(unsafe.Pointer(&buf[i])) + ppids[int(p.Pid)] = int(p.PPid) + } + + pid := os.Getppid() + for { + ppid := ppids[pid] + switch ppid { + case 0: + return 0 + case 1: + return pid + default: + pid = ppid + } + } +} + +func sysctlKernProcAll() ([]byte, error) { + const ( + CTRL_KERN = 1 + KERN_PROC = 14 + KERN_PROC_ALL = 0 + ) + + mib := [4]int32{CTRL_KERN, KERN_PROC, KERN_PROC_ALL, 0} + size := uintptr(0) + + _, _, errno := syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(len(mib)), + 0, + uintptr(unsafe.Pointer(&size)), + 0, + 0) + + if errno != 0 { + return nil, errno + } + + bs := make([]byte, size) + _, _, errno = syscall.Syscall6( + syscall.SYS___SYSCTL, + uintptr(unsafe.Pointer(&mib[0])), + uintptr(len(mib)), + uintptr(unsafe.Pointer(&bs[0])), + uintptr(unsafe.Pointer(&size)), + 0, + 0) + + if errno != 0 { + return nil, errno + } + return bs[0:size], nil +} diff --git a/internal/zenutil/window_unix.go b/internal/zenutil/window_unix.go new file mode 100644 index 0000000..d1598da --- /dev/null +++ b/internal/zenutil/window_unix.go @@ -0,0 +1,42 @@ +//go:build !windows && !darwin + +package zenutil + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "strconv" +) + +// ParseWindowId is internal. +func ParseWindowId(id string) int { + wid, _ := strconv.ParseUint(id, 0, 64) + return int(wid) +} + +// GetParentWindowId is internal. +func GetParentWindowId() int { + buf, err := exec.Command("ps", "-xo", "pid=,ppid=").CombinedOutput() + if err != nil { + return 0 + } + + ppids := map[int]int{} + reader := bytes.NewReader(buf) + for { + var pid, ppid int + _, err := fmt.Fscan(reader, &pid, &ppid) + if err == io.EOF { + break + } + if err != nil { + return 0 + } + ppids[pid] = ppid + } + + // Find the relevant pid and window id. + return 0 +} diff --git a/internal/zenutil/window_windows.go b/internal/zenutil/window_windows.go new file mode 100644 index 0000000..f661732 --- /dev/null +++ b/internal/zenutil/window_windows.go @@ -0,0 +1,14 @@ +package zenutil + +import "strconv" + +// ParseWindowId is internal. +func ParseWindowId(id string) uintptr { + hwnd, _ := strconv.ParseUint(id, 0, 64) + return uintptr(hwnd) +} + +// GetParentWindowId is internal. +func GetParentWindowId() int { + return 0 +}