Files
i3status-go/stdin.go
2024-01-12 00:43:49 +03:00

176 lines
3.7 KiB
Go

package main
import (
"bufio"
"encoding/json"
"log"
"os"
"strings"
)
// ClickEvent struct as described at https://i3wm.org/docs/i3bar-protocol.html
type ClickEvent struct {
Name string `json:"name,omitempty"`
Instance string `json:"instance,omitempty"`
Button int `json:"button"`
Modifiers []string `json:"modifiers"`
X int `json:"x"`
Y int `json:"y"`
RelativeX int `json:"relative_x"`
RelativeY int `json:"relative_y"`
OutputX int `json:"output_x"`
OutputY int `json:"output_y"`
Width int `json:"width"`
Height int `json:"height"`
}
// ParseStdin tries to parse text that i3bar prints to our stdin. Currently - it is mouse click events on different
// area names of i3bar.
func ParseStdin() {
reader := bufio.NewReader(os.Stdin)
// De-facto it is jsonl, except first line is garbage. Also, first symbol in each strint garbage too.
firstelem := true
for {
var e ClickEvent
buf, err := reader.ReadString('\n')
if err != nil {
if !firstelem {
log.Printf("Unable to read from stdin: %s", err)
}
break
}
if len(buf) == 0 {
log.Print("String from stdin has zero length, skipping")
continue
}
for i := 0; i < len(buf); i++ {
if strings.HasPrefix(buf, "{") {
break
}
buf = buf[1:]
}
if len(buf) == 0 {
log.Print("String from stdin has zero length, skipping")
continue
}
err = json.Unmarshal([]byte(buf), &e)
if err != nil {
if firstelem {
firstelem = false
} else {
log.Printf("Unable to decode json line from stdin: %s, buf: %s", err, buf)
}
continue
}
// Just in case.
if firstelem {
firstelem = false
}
// Clock clicks parse.
if e.Name == "wallclock" {
if Conf.Clock.LeftClick.Enabled && e.Button == 1 {
RunChan <- Conf.Clock.LeftClick.Cmd
} else if Conf.Clock.RightClick.Enabled && e.Button == 3 {
RunChan <- Conf.Clock.RightClick.Cmd
}
continue
}
if e.Name == "simple-volume-pa" {
if Conf.SimpleVolumePa.Enabled {
if e.Button == 3 {
RunChan <- Conf.SimpleVolumePa.RightClickCmd
continue
}
vol, err := pa.Volume()
if err != nil {
if err := PaReinit(); err != nil {
log.Printf("Unable to get pulseaudio volume: %s", err)
} else {
vol, err = pa.Volume()
if err != nil {
log.Printf("Unable to get volume pulseaudio server behaves weirdly: %s", err)
}
}
}
switch e.Button {
case Conf.SimpleVolumePa.WheelUp:
vol += float32(Conf.SimpleVolumePa.Step) / 100
if vol > (float32(Conf.SimpleVolumePa.MaxVolumeLimit) / 100) {
vol = float32(Conf.SimpleVolumePa.MaxVolumeLimit) / 100
}
if err := pa.SetVolume(vol); err != nil {
log.Printf("Unable to set pulseaudio volume: %s", err)
}
case Conf.SimpleVolumePa.WheelDown:
vol -= float32(Conf.SimpleVolumePa.Step) / 100
if vol < 0 {
vol = 0
}
if err := pa.SetVolume(vol); err != nil {
log.Printf("Unable to set pulseaudio volume: %s", err)
}
}
}
continue
}
if !Conf.AppButtons.Enabled {
continue
}
for _, app := range Conf.Apps {
switch {
case app.Name != "" && app.Instance != "":
if app.Name == e.Name && app.Instance == e.Instance {
prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...)
RunChan <- prg
break
}
case app.Name != "" && e.Name == app.Name:
prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...)
RunChan <- prg
case app.Instance != "" && e.Instance == app.Instance:
prg := append([]string{}, app.Cmd)
prg = append(prg, app.Args...)
RunChan <- prg
}
}
}
}