zenity/internal/zencmd/window_unix.go

112 lines
2 KiB
Go
Raw Normal View History

2022-06-09 08:35:02 -04:00
//go:build !windows && !darwin
2022-06-28 09:25:19 -04:00
package zencmd
2022-06-09 08:35:02 -04:00
import (
"bytes"
"fmt"
"io"
2022-11-14 08:11:14 -05:00
"math"
2022-06-09 08:35:02 -04:00
"os/exec"
"strconv"
2022-06-16 20:55:02 -04:00
"strings"
2022-06-09 08:35:02 -04:00
)
// ParseWindowId is internal.
func ParseWindowId(id string) int {
wid, _ := strconv.ParseUint(id, 0, 64)
2022-11-14 08:11:14 -05:00
return int(wid & math.MaxInt)
2022-06-09 08:35:02 -04:00
}
// GetParentWindowId is internal.
2022-06-16 20:55:02 -04:00
func GetParentWindowId(pid int) int {
winids, err := getPidToWindowMap()
2022-06-09 08:35:02 -04:00
if err != nil {
return 0
}
2022-06-16 20:55:02 -04:00
ppids, err := getPidToPpidMap()
if err != nil {
return 0
}
for {
if winid, ok := winids[pid]; ok {
id, _ := strconv.Atoi(winid)
return id
}
if ppid, ok := ppids[pid]; ok {
pid = ppid
} else {
return 0
}
}
}
func getPidToPpidMap() (map[int]int, error) {
out, err := exec.Command("ps", "-xo", "pid=,ppid=").Output()
if err != nil {
return nil, err
}
2022-06-09 08:35:02 -04:00
ppids := map[int]int{}
2022-06-16 20:55:02 -04:00
reader := bytes.NewReader(out)
2022-06-09 08:35:02 -04:00
for {
var pid, ppid int
_, err := fmt.Fscan(reader, &pid, &ppid)
if err == io.EOF {
break
}
if err != nil {
2022-06-16 20:55:02 -04:00
return nil, err
2022-06-09 08:35:02 -04:00
}
ppids[pid] = ppid
}
2022-06-16 20:55:02 -04:00
return ppids, nil
}
2022-06-09 08:35:02 -04:00
2022-06-16 20:55:02 -04:00
func getPidToWindowMap() (map[int]string, error) {
ids, err := getWindowIDs()
if err != nil {
return nil, err
}
var pid int
winids := map[int]string{}
for _, id := range ids {
pid, err = getWindowPid(id)
if err != nil {
continue
}
winids[pid] = id
}
if err != nil && len(winids) == 0 {
return nil, err
}
return winids, nil
}
func getWindowIDs() ([]string, error) {
out, err := exec.Command("xprop", "-root", "0i", "\t$0+", "_NET_CLIENT_LIST").Output()
if err != nil {
return nil, err
}
2023-01-10 09:26:14 -05:00
if _, out, cut := bytes.Cut(out, []byte("\t")); cut {
return strings.Split(string(out), ", "), nil
2022-06-16 20:55:02 -04:00
}
2023-01-10 09:26:14 -05:00
return nil, fmt.Errorf("xprop: unexpected output: %q", out)
2022-06-16 20:55:02 -04:00
}
func getWindowPid(id string) (int, error) {
out, err := exec.Command("xprop", "-id", id, "0i", "\t$0", "_NET_WM_PID").Output()
if err != nil {
return 0, err
}
2023-01-10 09:26:14 -05:00
if _, out, cut := bytes.Cut(out, []byte("\t")); cut {
return strconv.Atoi(string(out))
2022-06-16 20:55:02 -04:00
}
2023-01-10 09:26:14 -05:00
return 0, fmt.Errorf("xprop: unexpected output: %q", out)
2022-06-09 08:35:02 -04:00
}