Initial commit

This commit is contained in:
eleksir
2024-01-06 18:33:44 +03:00
commit d85dc5d5bb
657 changed files with 262300 additions and 0 deletions

25
vendor/go.i3wm.org/i3/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,25 @@
# Use the (faster) container-based infrastructure, see also
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
sudo: false
dist: trusty
services:
- docker
language: go
go:
- "1.12"
go_import_path: go.i3wm.org/i3
env:
global:
- secure: "c9Q/SwO3gQ0rCJDCk9V9NgchFVCUj5+dIJbKqUcbXpdtaG8WLNWEamrv4nqbrLWw/I9Zw9St4VErqbqxU4Fee9ftt+PBbtMOi/eZ6LbnnDjJCYnz912Wf7v05L5Ghl1WNf8ajNCjvBpsJMe6UixBmZHeBqSin5OUT55gN+wMi68VaxTbo0DchXjuU7hXfDvV4iVvmtQmP9C4yQDz9HiEdaDz9SP0HNCzngONikld8rGSRX+V2XyaJsd13hJQM0ZfCXuRS0J0OBLz3msiSbobuWUzApI/s81AHUdkj3JbXfrxaA0kj75fZquqFyTaiNQRjKVqwXGGaMWcVNFOeDv3l5n6HMuImjxEypDwFcjbDo/9ivGeG31f7oh+lB/JkhRoZmW6tiIlRSy4rdVKmzn0ENIvxPcEFzqoLdail5ffM/b7KS2eGetTG/86PaLbk4XoQDzVcOWgOjeNn/meOAgUBEEMauZQZhF57Bs7ev62BReu8PbTXTyCVhpR77oAnt9dfW1tEQTrUBH9vG32V+/aC6YmrD/NM4t4VpvyJr/npXGyTW9JJ9bPLfHZEXjdoyOtBPNuousa7rM6hD2hbQ+/lVuEZp2c2RIIpuP5cG4MzHmA4W1GsDRbm/zG87VKt2zaKA2tuXPULDvlux49zI19OZB7sSYm3RgVN/+6YhYPwSs=" # PERSIST_URL
script:
# Check whether files are syntactically correct.
- "gofmt -l $(find . -name '*.go' | tr '\\n' ' ') >/dev/null"
# Check whether files were not gofmt'ed.
- "gosrc=$(find . -name '*.go' | tr '\\n' ' '); [ $(gofmt -l $gosrc 2>&- | wc -l) -eq 0 ] || (echo 'gofmt was not run on these files:'; gofmt -l $gosrc 2>&-; false)"
- go vet .
- go test -c
- docker build --pull --no-cache --rm -t=goi3 -f travis/Dockerfile .
- docker run -v $PWD:/usr/src goi3 /bin/sh -c 'strace -f -o st -s 2048 -v -y ./i3.test -test.v' || curl --data-binary @st -X PUT $PERSIST_URL

27
vendor/go.i3wm.org/i3/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,27 @@
Copyright © 2017, Michael Stapelberg and contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Michael Stapelberg nor the
names of contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Michael Stapelberg ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Michael Stapelberg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

60
vendor/go.i3wm.org/i3/README.md generated vendored Normal file
View File

@@ -0,0 +1,60 @@
[![Build Status](https://travis-ci.org/i3/go-i3.svg?branch=master)](https://travis-ci.org/i3/go-i3)
[![Go Report Card](https://goreportcard.com/badge/go.i3wm.org/i3)](https://goreportcard.com/report/go.i3wm.org/i3)
[![GoDoc](https://godoc.org/go.i3wm.org/i3?status.svg)](https://godoc.org/go.i3wm.org/i3)
Package i3 provides a convenient interface to the i3 window manager via [its IPC
interface](https://i3wm.org/docs/ipc.html).
See [its documentation](https://godoc.org/go.i3wm.org/i3) for more details.
## Advantages over other i3 IPC packages
Here comes a grab bag of features to which we paid attention. At the time of
writing, most other i3 IPC packages lack at least a good number of these
features:
* Retries are transparently handled: programs using this package will recover
automatically from in-place i3 restarts. Additionally, programs can be started
from xsession or user sessions before i3 is even running.
* Version checks are transparently handled: if your program uses features which
are not supported by the running i3 version, helpful error messages will be
returned at run time.
* Comprehensive: the entire documented IPC interface of the latest stable i3
version is covered by this package. Tagged releases match i3’s major and minor
version.
* Consistent and familiar: once familiar with the i3 IPC protocol’s features,
you should have no trouble matching the documentation to API and vice-versa.
* Good test coverage (hard to display in a badge, as our multi-process setup
breaks `go test`’s `-coverprofile` flag).
* Implemented in pure Go, without resorting to the `unsafe` package.
* Works on little and big endian architectures.
## Scope
i3’s entire documented IPC interface is available in this package.
In addition, helper functions which are useful for a broad range of programs
(and only those!) are provided, e.g. Node’s FindChild and FindFocused.
Packages which introduce higher-level abstractions should feel free to use this
package as a building block.
## Assumptions
* The `i3(1)` binary must be in `$PATH` so that the IPC socket path can be retrieved.
* For transparent version checks to work, the running i3 version must be ≥ 4.3 (released 2012-09-19).
## Testing
Be sure to include the target i3 version (the most recent stable release) in
`$PATH` and use `go test` as usual:
```shell
PATH=~/i3/build/i3:$PATH go test -v go.i3wm.org/i3
```

111
vendor/go.i3wm.org/i3/barconfig.go generated vendored Normal file
View File

@@ -0,0 +1,111 @@
package i3
import "encoding/json"
// BarConfigColors describes a serialized bar colors configuration block.
//
// See https://i3wm.org/docs/ipc.html#_bar_config_reply for more details.
type BarConfigColors struct {
Background string `json:"background"`
Statusline string `json:"statusline"`
Separator string `json:"separator"`
FocusedBackground string `json:"focused_background"`
FocusedStatusline string `json:"focused_statusline"`
FocusedSeparator string `json:"focused_separator"`
FocusedWorkspaceText string `json:"focused_workspace_text"`
FocusedWorkspaceBackground string `json:"focused_workspace_bg"`
FocusedWorkspaceBorder string `json:"focused_workspace_border"`
ActiveWorkspaceText string `json:"active_workspace_text"`
ActiveWorkspaceBackground string `json:"active_workspace_bg"`
ActiveWorkspaceBorder string `json:"active_workspace_border"`
InactiveWorkspaceText string `json:"inactive_workspace_text"`
InactiveWorkspaceBackground string `json:"inactive_workspace_bg"`
InactiveWorkspaceBorder string `json:"inactive_workspace_border"`
UrgentWorkspaceText string `json:"urgent_workspace_text"`
UrgentWorkspaceBackground string `json:"urgent_workspace_bg"`
UrgentWorkspaceBorder string `json:"urgent_workspace_border"`
BindingModeText string `json:"binding_mode_text"`
BindingModeBackground string `json:"binding_mode_bg"`
BindingModeBorder string `json:"binding_mode_border"`
}
// BarConfig describes a serialized bar configuration block.
//
// See https://i3wm.org/docs/ipc.html#_bar_config_reply for more details.
type BarConfig struct {
ID string `json:"id"`
Mode string `json:"mode"`
Position string `json:"position"`
StatusCommand string `json:"status_command"`
Font string `json:"font"`
WorkspaceButtons bool `json:"workspace_buttons"`
BindingModeIndicator bool `json:"binding_mode_indicator"`
Verbose bool `json:"verbose"`
Colors BarConfigColors `json:"colors"`
}
// GetBarIDs returns an array of configured bar IDs.
//
// GetBarIDs is supported in i3 ≥ v4.1 (2011-11-11).
func GetBarIDs() ([]string, error) {
reply, err := roundTrip(messageTypeGetBarConfig, nil)
if err != nil {
return nil, err
}
var ids []string
err = json.Unmarshal(reply.Payload, &ids)
return ids, err
}
// GetBarConfig returns the configuration for the bar with the specified barID.
//
// Obtain the barID from GetBarIDs.
//
// GetBarConfig is supported in i3 ≥ v4.1 (2011-11-11).
func GetBarConfig(barID string) (BarConfig, error) {
reply, err := roundTrip(messageTypeGetBarConfig, []byte(barID))
if err != nil {
return BarConfig{}, err
}
cfg := BarConfig{
Colors: BarConfigColors{
Background: "#000000",
Statusline: "#ffffff",
Separator: "#666666",
FocusedBackground: "#000000",
FocusedStatusline: "#ffffff",
FocusedSeparator: "#666666",
FocusedWorkspaceText: "#4c7899",
FocusedWorkspaceBackground: "#285577",
FocusedWorkspaceBorder: "#ffffff",
ActiveWorkspaceText: "#333333",
ActiveWorkspaceBackground: "#5f676a",
ActiveWorkspaceBorder: "#ffffff",
InactiveWorkspaceText: "#333333",
InactiveWorkspaceBackground: "#222222",
InactiveWorkspaceBorder: "#888888",
UrgentWorkspaceText: "#2f343a",
UrgentWorkspaceBackground: "#900000",
UrgentWorkspaceBorder: "#ffffff",
BindingModeText: "#2f343a",
BindingModeBackground: "#900000",
BindingModeBorder: "#ffffff",
},
}
err = json.Unmarshal(reply.Payload, &cfg)
return cfg, err
}

17
vendor/go.i3wm.org/i3/bindingmodes.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package i3
import "encoding/json"
// GetBindingModes returns the names of all currently configured binding modes.
//
// GetBindingModes is supported in i3 ≥ v4.13 (2016-11-08).
func GetBindingModes() ([]string, error) {
reply, err := roundTrip(messageTypeGetBindingModes, nil)
if err != nil {
return nil, err
}
var bm []string
err = json.Unmarshal(reply.Payload, &bm)
return bm, err
}

63
vendor/go.i3wm.org/i3/byteorder.go generated vendored Normal file
View File

@@ -0,0 +1,63 @@
package i3
import (
"encoding/binary"
"io"
"strings"
)
// detectByteOrder sends messages to i3 to determine the byte order it uses.
// For details on this technique, see:
// https://build.i3wm.org/docs/ipc.html#_appendix_a_detecting_byte_order_in_memory_safe_languages
func detectByteOrder(conn io.ReadWriter) (binary.ByteOrder, error) {
const (
// targetLen is 0x00 01 01 00 in both, big and little endian
targetLen = 65536 + 256
// SUBSCRIBE was introduced in 3.e (2010-03-30)
prefixSubscribe = "[]"
// RUN_COMMAND was always present
prefixCmd = "nop byte-order detection. padding: "
)
// 2. Send a big endian encoded message of type SUBSCRIBE:
payload := []byte(prefixSubscribe + strings.Repeat(" ", targetLen-len(prefixSubscribe)))
if err := binary.Write(conn, binary.BigEndian, &header{magic, uint32(len(payload)), messageTypeSubscribe}); err != nil {
return nil, err
}
if _, err := conn.Write(payload); err != nil {
return nil, err
}
// 3. Send a byte order independent RUN_COMMAND message:
payload = []byte(prefixCmd + strings.Repeat("a", targetLen-len(prefixCmd)))
if err := binary.Write(conn, binary.BigEndian, &header{magic, uint32(len(payload)), messageTypeRunCommand}); err != nil {
return nil, err
}
if _, err := conn.Write(payload); err != nil {
return nil, err
}
// 4. Receive a message header, decode the message type as big endian:
var header [14]byte
if _, err := io.ReadFull(conn, header[:]); err != nil {
return nil, err
}
if messageType(binary.BigEndian.Uint32(header[10:14])) == messageReplyTypeCommand {
order := binary.LittleEndian // our big endian message was not answered
// Read remaining payload
_, err := io.ReadFull(conn, make([]byte, order.Uint32(header[6:10])))
return order, err
}
order := binary.BigEndian // our big endian message was answered
// Read remaining payload
if _, err := io.ReadFull(conn, make([]byte, order.Uint32(header[6:10]))); err != nil {
return order, err
}
// Slurp the pending RUN_COMMAND reply.
sock := &socket{conn: conn, order: order}
_, err := sock.recvMsg()
return binary.BigEndian, err
}

64
vendor/go.i3wm.org/i3/command.go generated vendored Normal file
View File

@@ -0,0 +1,64 @@
package i3
import (
"encoding/json"
"fmt"
)
// CommandResult always contains Success, and command-specific fields where
// appropriate.
type CommandResult struct {
// Success indicates whether the command was run without any errors.
Success bool `json:"success"`
// Error is a human-readable error message, non-empty for unsuccessful
// commands.
Error string `json:"error"`
}
// IsUnsuccessful is a convenience function which can be used to check if an
// error is a CommandUnsuccessfulError.
func IsUnsuccessful(err error) bool {
_, ok := err.(*CommandUnsuccessfulError)
return ok
}
// CommandUnsuccessfulError is returned by RunCommand for unsuccessful
// commands. This type is exported so that you can ignore this error if you
// expect your command(s) to fail.
type CommandUnsuccessfulError struct {
command string
cr CommandResult
}
// Error implements error.
func (e *CommandUnsuccessfulError) Error() string {
return fmt.Sprintf("command %q unsuccessful: %v", e.command, e.cr.Error)
}
// RunCommand makes i3 run the specified command.
//
// Error is non-nil if any CommandResult.Success is not true. See IsUnsuccessful
// if you send commands which are expected to fail.
//
// RunCommand is supported in i3 ≥ v4.0 (2011-07-31).
func RunCommand(command string) ([]CommandResult, error) {
reply, err := roundTrip(messageTypeRunCommand, []byte(command))
if err != nil {
return []CommandResult{}, err
}
var crs []CommandResult
err = json.Unmarshal(reply.Payload, &crs)
if err == nil {
for _, cr := range crs {
if !cr.Success {
return crs, &CommandUnsuccessfulError{
command: command,
cr: cr,
}
}
}
}
return crs, err
}

24
vendor/go.i3wm.org/i3/config.go generated vendored Normal file
View File

@@ -0,0 +1,24 @@
package i3
import "encoding/json"
// Config contains details about the configuration file.
//
// See https://i3wm.org/docs/ipc.html#_config_reply for more details.
type Config struct {
Config string `json:"config"`
}
// GetConfig returns i3’s in-memory copy of the configuration file contents.
//
// GetConfig is supported in i3 ≥ v4.14 (2017-09-04).
func GetConfig() (Config, error) {
reply, err := roundTrip(messageTypeGetConfig, nil)
if err != nil {
return Config{}, err
}
var cfg Config
err = json.Unmarshal(reply.Payload, &cfg)
return cfg, err
}

22
vendor/go.i3wm.org/i3/doc.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
// Package i3 provides a convenient interface to the i3 window manager.
//
// Its function and type names don’t stutter, and all functions and methods are
// safe for concurrent use (except where otherwise noted). The package does not
// import "unsafe" and hence should be widely applicable.
//
// UNIX socket connections to i3 are transparently managed by the package. Upon
// any read/write errors on a UNIX socket, the package transparently retries for
// up to 10 seconds, but only as long as the i3 process keeps running.
//
// The package is published in versioned releases, where the major and minor
// version are identical to the i3 release the package is compatible with
// (e.g. 4.14 implements the entire documented IPC interface of i3 4.14).
//
// This package will only ever receive additions, so versioning should only be
// relevant to you if you are interested in a recently-introduced IPC feature.
//
// Message type functions and event types are annotated with the i3 version in
// which they were introduced. Under the covers, they use AtLeast, so they
// return a helpful error message at runtime if the running i3 version is too
// old.
package i3 // import "go.i3wm.org/i3"

44
vendor/go.i3wm.org/i3/getpid.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
package i3
import (
"sync"
"github.com/BurntSushi/xgbutil"
"github.com/BurntSushi/xgbutil/xprop"
)
func i3Pid() int {
xu, err := xgbutil.NewConn()
if err != nil {
return -1 // X session terminated
}
defer xu.Conn().Close()
reply, err := xprop.GetProperty(xu, xu.RootWin(), "I3_PID")
if err != nil {
return -1 // I3_PID no longer present (X session replaced?)
}
num, err := xprop.PropValNum(reply, err)
if err != nil {
return -1
}
return int(num)
}
var lastPid struct {
sync.Mutex
pid int
}
// IsRunningHook provides a method to override the method which detects if i3 is running or not
var IsRunningHook = func() bool {
lastPid.Lock()
defer lastPid.Unlock()
if !wasRestart || lastPid.pid == 0 {
lastPid.pid = i3Pid()
}
return pidValid(lastPid.pid)
}
func i3Running() bool {
return IsRunningHook()
}

17
vendor/go.i3wm.org/i3/marks.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package i3
import "encoding/json"
// GetMarks returns the names of all currently set marks.
//
// GetMarks is supported in i3 ≥ v4.1 (2011-11-11).
func GetMarks() ([]string, error) {
reply, err := roundTrip(messageTypeGetMarks, nil)
if err != nil {
return nil, err
}
var marks []string
err = json.Unmarshal(reply.Payload, &marks)
return marks, err
}

28
vendor/go.i3wm.org/i3/outputs.go generated vendored Normal file
View File

@@ -0,0 +1,28 @@
package i3
import "encoding/json"
// Output describes an i3 output.
//
// See https://i3wm.org/docs/ipc.html#_outputs_reply for more details.
type Output struct {
Name string `json:"name"`
Active bool `json:"active"`
Primary bool `json:"primary"`
CurrentWorkspace string `json:"current_workspace"`
Rect Rect `json:"rect"`
}
// GetOutputs returns i3’s current outputs.
//
// GetOutputs is supported in i3 ≥ v4.0 (2011-07-31).
func GetOutputs() ([]Output, error) {
reply, err := roundTrip(messageTypeGetOutputs, nil)
if err != nil {
return nil, err
}
var outputs []Output
err = json.Unmarshal(reply.Payload, &outputs)
return outputs, err
}

198
vendor/go.i3wm.org/i3/socket.go generated vendored Normal file
View File

@@ -0,0 +1,198 @@
package i3
import (
"encoding/binary"
"fmt"
"io"
"math/rand"
"net"
"os/exec"
"strings"
"sync"
"time"
)
// If your computer takes more than 10s to restart i3, it must be seriously
// overloaded, in which case we are probably doing you a favor by erroring out.
const reconnectTimeout = 10 * time.Second
// remote is a singleton containing the socket path and auto-detected byte order
// which i3 is using. It is lazily initialized by getIPCSocket.
var remote struct {
path string
order binary.ByteOrder
mu sync.Mutex
}
// SocketPathHook Provides a way to override the default socket path lookup mechanism. Overriding this is unsupported.
var SocketPathHook = func() (string, error) {
out, err := exec.Command("i3", "--get-socketpath").CombinedOutput()
if err != nil {
return "", fmt.Errorf("getting i3 socketpath: %v (output: %s)", err, out)
}
return string(out), nil
}
func getIPCSocket(updateSocketPath bool) (*socket, net.Conn, error) {
remote.mu.Lock()
defer remote.mu.Unlock()
path := remote.path
if (!wasRestart && updateSocketPath) || remote.path == "" {
out, err := SocketPathHook()
if err != nil {
return nil, nil, err
}
path = strings.TrimSpace(string(out))
}
conn, err := net.Dial("unix", path)
if err != nil {
return nil, nil, err
}
remote.path = path
if remote.order == nil {
remote.order, err = detectByteOrder(conn)
if err != nil {
conn.Close()
return nil, nil, err
}
}
return &socket{conn: conn, order: remote.order}, conn, err
}
type messageType uint32
const (
messageTypeRunCommand messageType = iota
messageTypeGetWorkspaces
messageTypeSubscribe
messageTypeGetOutputs
messageTypeGetTree
messageTypeGetMarks
messageTypeGetBarConfig
messageTypeGetVersion
messageTypeGetBindingModes
messageTypeGetConfig
messageTypeSendTick
messageTypeSync
)
var messageAtLeast = map[messageType]majorMinor{
messageTypeRunCommand: {4, 0},
messageTypeGetWorkspaces: {4, 0},
messageTypeSubscribe: {4, 0},
messageTypeGetOutputs: {4, 0},
messageTypeGetTree: {4, 0},
messageTypeGetMarks: {4, 1},
messageTypeGetBarConfig: {4, 1},
messageTypeGetVersion: {4, 3},
messageTypeGetBindingModes: {4, 13},
messageTypeGetConfig: {4, 14},
messageTypeSendTick: {4, 15},
messageTypeSync: {4, 16},
}
const (
messageReplyTypeCommand messageType = iota
messageReplyTypeWorkspaces
messageReplyTypeSubscribe
)
var magic = [6]byte{'i', '3', '-', 'i', 'p', 'c'}
type header struct {
Magic [6]byte
Length uint32
Type messageType
}
type message struct {
Type messageType
Payload []byte
}
type socket struct {
conn io.ReadWriter
order binary.ByteOrder
}
func (s *socket) recvMsg() (message, error) {
if s == nil {
return message{}, fmt.Errorf("not connected")
}
var h header
if err := binary.Read(s.conn, s.order, &h); err != nil {
return message{}, err
}
msg := message{
Type: h.Type,
Payload: make([]byte, h.Length),
}
_, err := io.ReadFull(s.conn, msg.Payload)
return msg, err
}
func (s *socket) roundTrip(t messageType, payload []byte) (message, error) {
if s == nil {
return message{}, fmt.Errorf("not connected")
}
if err := binary.Write(s.conn, s.order, &header{magic, uint32(len(payload)), t}); err != nil {
return message{}, err
}
if len(payload) > 0 { // skip empty Write()s for net.Pipe
_, err := s.conn.Write(payload)
if err != nil {
return message{}, err
}
}
return s.recvMsg()
}
// defaultSock is a singleton, lazily initialized by roundTrip. All
// request/response messages are sent to i3 via this socket, whereas
// subscriptions use their own connection.
var defaultSock struct {
sock *socket
conn net.Conn
mu sync.Mutex
}
// roundTrip sends a message to i3 and returns the received result in a
// concurrency-safe fashion.
func roundTrip(t messageType, payload []byte) (message, error) {
// Error out early in case the message type is not yet supported by the
// running i3 version.
if t != messageTypeGetVersion {
if err := AtLeast(messageAtLeast[t].major, messageAtLeast[t].minor); err != nil {
return message{}, err
}
}
defaultSock.mu.Lock()
defer defaultSock.mu.Unlock()
Outer:
for {
msg, err := defaultSock.sock.roundTrip(t, payload)
if err == nil {
return msg, nil // happy path: success
}
// reconnect
start := time.Now()
for time.Since(start) < reconnectTimeout && (defaultSock.sock == nil || i3Running()) {
if defaultSock.sock != nil {
defaultSock.conn.Close()
}
defaultSock.sock, defaultSock.conn, err = getIPCSocket(defaultSock.sock != nil)
if err == nil {
continue Outer
}
// Reconnect within [10, 20) ms to prevent CPU-starving i3.
time.Sleep(time.Duration(10+rand.Int63n(10)) * time.Millisecond)
}
return msg, err
}
}

382
vendor/go.i3wm.org/i3/subscribe.go generated vendored Normal file
View File

@@ -0,0 +1,382 @@
package i3
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"net"
"time"
)
// Event is an event received from i3.
//
// Type-assert or type-switch on Event to obtain a more specific type.
type Event interface{}
// WorkspaceEvent contains details about various workspace-related changes.
//
// See https://i3wm.org/docs/ipc.html#_workspace_event for more details.
type WorkspaceEvent struct {
Change string `json:"change"`
Current Node `json:"current"`
Old Node `json:"old"`
}
// OutputEvent contains details about various output-related changes.
//
// See https://i3wm.org/docs/ipc.html#_output_event for more details.
type OutputEvent struct {
Change string `json:"change"`
}
// ModeEvent contains details about various mode-related changes.
//
// See https://i3wm.org/docs/ipc.html#_mode_event for more details.
type ModeEvent struct {
Change string `json:"change"`
PangoMarkup bool `json:"pango_markup"`
}
// WindowEvent contains details about various window-related changes.
//
// See https://i3wm.org/docs/ipc.html#_window_event for more details.
type WindowEvent struct {
Change string `json:"change"`
Container Node `json:"container"`
}
// BarconfigUpdateEvent contains details about various bar config-related changes.
//
// See https://i3wm.org/docs/ipc.html#_barconfig_update_event for more details.
type BarconfigUpdateEvent BarConfig
// BindingEvent contains details about various binding-related changes.
//
// See https://i3wm.org/docs/ipc.html#_binding_event for more details.
type BindingEvent struct {
Change string `json:"change"`
Binding struct {
Command string `json:"command"`
EventStateMask []string `json:"event_state_mask"`
InputCode int64 `json:"input_code"`
Symbol string `json:"symbol"`
InputType string `json:"input_type"`
} `json:"binding"`
}
// ShutdownEvent contains the reason for which the IPC connection is about to be
// shut down.
//
// See https://i3wm.org/docs/ipc.html#_shutdown_event for more details.
type ShutdownEvent struct {
Change string `json:"change"`
}
// TickEvent contains the payload of the last tick command.
//
// See https://i3wm.org/docs/ipc.html#_tick_event for more details.
type TickEvent struct {
First bool `json:"first"`
Payload string `json:"payload"`
}
type eventReplyType int
const (
eventReplyTypeWorkspace eventReplyType = iota
eventReplyTypeOutput
eventReplyTypeMode
eventReplyTypeWindow
eventReplyTypeBarconfigUpdate
eventReplyTypeBinding
eventReplyTypeShutdown
eventReplyTypeTick
)
const (
eventFlagMask = uint32(0x80000000)
eventTypeMask = ^eventFlagMask
)
// EventReceiver is not safe for concurrent use.
type EventReceiver struct {
types []EventType // for re-subscribing on io.EOF
sock *socket
conn net.Conn
ev Event
err error
reconnect bool
}
// Event returns the most recent event received from i3 by a call to Next.
func (r *EventReceiver) Event() Event {
return r.ev
}
func (r *EventReceiver) subscribe() error {
var err error
if r.conn != nil {
r.conn.Close()
}
if wasRestart {
r.reconnect = false
}
r.sock, r.conn, err = getIPCSocket(r.reconnect)
r.reconnect = true
if err != nil {
return err
}
payload, err := json.Marshal(r.types)
if err != nil {
return err
}
b, err := r.sock.roundTrip(messageTypeSubscribe, payload)
if err != nil {
return err
}
var reply struct {
Success bool `json:"success"`
}
if err := json.Unmarshal(b.Payload, &reply); err != nil {
return err
}
if !reply.Success {
return fmt.Errorf("could not subscribe, check the i3 log")
}
r.err = nil
return nil
}
func (r *EventReceiver) next() (Event, error) {
reply, err := r.sock.recvMsg()
if err != nil {
return nil, err
}
if (uint32(reply.Type) & eventFlagMask) == 0 {
return nil, fmt.Errorf("unexpectedly did not receive an event")
}
t := uint32(reply.Type) & eventTypeMask
switch eventReplyType(t) {
case eventReplyTypeWorkspace:
var e WorkspaceEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeOutput:
var e OutputEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeMode:
var e ModeEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeWindow:
var e WindowEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeBarconfigUpdate:
var e BarconfigUpdateEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeBinding:
var e BindingEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeShutdown:
var e ShutdownEvent
return &e, json.Unmarshal(reply.Payload, &e)
case eventReplyTypeTick:
var e TickEvent
return &e, json.Unmarshal(reply.Payload, &e)
}
return nil, fmt.Errorf("BUG: event reply type %d not implemented yet", t)
}
// Next advances the EventReceiver to the next event, which will then be
// available through the Event method. It returns false when reaching an
// error. After Next returns false, the Close method will return the first
// error.
//
// Until you call Close, you must call Next in a loop for every EventReceiver
// (usually in a separate goroutine), otherwise i3 will deadlock as soon as the
// UNIX socket buffer is full of unprocessed events.
func (r *EventReceiver) Next() bool {
Outer:
for r.err == nil {
r.ev, r.err = r.next()
if r.err == nil {
return true // happy path
}
// reconnect
start := time.Now()
for time.Since(start) < reconnectTimeout && (r.sock == nil || i3Running()) {
if err := r.subscribe(); err == nil {
continue Outer
} else {
r.err = err
}
// Reconnect within [10, 20) ms to prevent CPU-starving i3.
time.Sleep(time.Duration(10+rand.Int63n(10)) * time.Millisecond)
}
}
return r.err == nil
}
// Close closes the connection to i3. If you don’t ever call Close, you must
// consume events via Next to prevent i3 from deadlocking.
func (r *EventReceiver) Close() error {
if r.conn != nil {
if r.err == nil {
r.err = r.conn.Close()
} else {
// Retain the original error.
r.conn.Close()
}
r.conn = nil
r.sock = nil
}
return r.err
}
// EventType indicates the specific kind of event to subscribe to.
type EventType string
// i3 currently implements the following event types:
const (
WorkspaceEventType EventType = "workspace" // since 4.0
OutputEventType EventType = "output" // since 4.0
ModeEventType EventType = "mode" // since 4.4
WindowEventType EventType = "window" // since 4.5
BarconfigUpdateEventType EventType = "barconfig_update" // since 4.6
BindingEventType EventType = "binding" // since 4.9
ShutdownEventType EventType = "shutdown" // since 4.14
TickEventType EventType = "tick" // since 4.15
)
type majorMinor struct {
major int64
minor int64
}
var eventAtLeast = map[EventType]majorMinor{
WorkspaceEventType: {4, 0},
OutputEventType: {4, 0},
ModeEventType: {4, 4},
WindowEventType: {4, 5},
BarconfigUpdateEventType: {4, 6},
BindingEventType: {4, 9},
ShutdownEventType: {4, 14},
TickEventType: {4, 15},
}
// Subscribe returns an EventReceiver for receiving events of the specified
// types from i3.
//
// Unless the ordering of events matters to your use-case, you are encouraged to
// call Subscribe once per event type, so that you can use type assertions
// instead of type switches.
//
// Subscribe is supported in i3 ≥ v4.0 (2011-07-31).
func Subscribe(eventTypes ...EventType) *EventReceiver {
// Error out early in case any requested event type is not yet supported by
// the running i3 version.
for _, t := range eventTypes {
if err := AtLeast(eventAtLeast[t].major, eventAtLeast[t].minor); err != nil {
return &EventReceiver{err: err}
}
}
return &EventReceiver{types: eventTypes}
}
// restart runs the restart i3 command without entering an infinite loop: as
// RUN_COMMAND with payload "restart" does not result in a reply, we subscribe
// to the shutdown event beforehand (on a dedicated connection), which we can
// receive instead of a reply.
func restart(firstAttempt bool) error {
sock, conn, err := getIPCSocket(!firstAttempt)
if err != nil {
return err
}
defer conn.Close()
payload, err := json.Marshal([]EventType{ShutdownEventType})
if err != nil {
return err
}
b, err := sock.roundTrip(messageTypeSubscribe, payload)
if err != nil {
return err
}
var sreply struct {
Success bool `json:"success"`
}
if err := json.Unmarshal(b.Payload, &sreply); err != nil {
return err
}
if !sreply.Success {
return fmt.Errorf("could not subscribe, check the i3 log")
}
rreply, err := sock.roundTrip(messageTypeRunCommand, []byte("restart"))
if err != nil {
return err
}
if (uint32(rreply.Type) & eventFlagMask) == 0 {
var crs []CommandResult
err = json.Unmarshal(rreply.Payload, &crs)
if err == nil {
for _, cr := range crs {
if !cr.Success {
return &CommandUnsuccessfulError{
command: "restart",
cr: cr,
}
}
}
}
return nil // restart command successful
}
t := uint32(rreply.Type) & eventTypeMask
if got, want := eventReplyType(t), eventReplyTypeShutdown; got != want {
return fmt.Errorf("unexpected reply type: got %d, want %d", got, want)
}
return nil // shutdown event received
}
var wasRestart = false
// Restart sends the restart command to i3. Sending restart via RunCommand will
// result in a deadlock: since i3 restarts before it sends the reply to the
// restart command, RunCommand will retry the command indefinitely.
//
// Restart is supported in i3 ≥ v4.14 (2017-09-04).
func Restart() error {
if err := AtLeast(eventAtLeast[ShutdownEventType].major, eventAtLeast[ShutdownEventType].minor); err != nil {
return err
}
// TODO(https://github.com/i3/i3/pull/3743): conditionally use this approach
// once the restart reply PR made it into an i3 release:
if false {
_, err := roundTrip(messageTypeRunCommand, []byte("restart"))
return err
}
log.Println("preventing any further X11 connections to work around issue #3")
wasRestart = true
var (
firstAttempt = true
start = time.Now()
lastErr error
)
for time.Since(start) < reconnectTimeout && (firstAttempt || i3Running()) {
lastErr = restart(firstAttempt)
if lastErr == nil {
return nil // success
}
firstAttempt = false
}
return lastErr
}

32
vendor/go.i3wm.org/i3/sync.go generated vendored Normal file
View File

@@ -0,0 +1,32 @@
package i3
import "encoding/json"
// SyncRequest represents the payload of a Sync request.
type SyncRequest struct {
Window uint32 `json:"window"` // X11 window id
Rnd uint32 `json:"rnd"` // Random value for distinguishing requests
}
// SyncResult attests the sync command was successful.
type SyncResult struct {
Success bool `json:"success"`
}
// Sync sends a tick event with the provided payload.
//
// Sync is supported in i3 ≥ v4.16 (2018-11-04).
func Sync(req SyncRequest) (SyncResult, error) {
b, err := json.Marshal(req)
if err != nil {
return SyncResult{}, err
}
reply, err := roundTrip(messageTypeSync, b)
if err != nil {
return SyncResult{}, err
}
var tr SyncResult
err = json.Unmarshal(reply.Payload, &tr)
return tr, err
}

22
vendor/go.i3wm.org/i3/tick.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
package i3
import "encoding/json"
// TickResult attests the tick command was successful.
type TickResult struct {
Success bool `json:"success"`
}
// SendTick sends a tick event with the provided payload.
//
// SendTick is supported in i3 ≥ v4.15 (2018-03-10).
func SendTick(command string) (TickResult, error) {
reply, err := roundTrip(messageTypeSendTick, []byte(command))
if err != nil {
return TickResult{}, err
}
var tr TickResult
err = json.Unmarshal(reply.Payload, &tr)
return tr, err
}

164
vendor/go.i3wm.org/i3/tree.go generated vendored Normal file
View File

@@ -0,0 +1,164 @@
package i3
import (
"encoding/json"
)
// NodeType indicates the specific kind of Node.
type NodeType string
// i3 currently implements the following node types:
const (
Root NodeType = "root"
OutputNode NodeType = "output"
Con NodeType = "con"
FloatingCon NodeType = "floating_con"
WorkspaceNode NodeType = "workspace"
DockareaNode NodeType = "dockarea"
)
// Layout indicates the layout of a Node.
type Layout string
// i3 currently implements the following layouts:
const (
SplitH Layout = "splith"
SplitV Layout = "splitv"
Stacked Layout = "stacked"
Tabbed Layout = "tabbed"
DockareaLayout Layout = "dockarea"
OutputLayout Layout = "output"
)
// BorderStyle indicates the border style of a node.
type BorderStyle string
// i3 currently implements the following border styles:
const (
NormalBorder BorderStyle = "normal"
NoBorder BorderStyle = "none"
PixelBorder BorderStyle = "pixel"
)
// Rect is a rectangle, used for various dimensions in Node, for example.
type Rect struct {
X int64 `json:"x"`
Y int64 `json:"y"`
Width int64 `json:"width"`
Height int64 `json:"height"`
}
// WindowProperties correspond to X11 window properties
//
// See https://build.i3wm.org/docs/ipc.html#_tree_reply
type WindowProperties struct {
Title string `json:"title"`
Instance string `json:"instance"`
Class string `json:"class"`
Role string `json:"window_role"`
Transient NodeID `json:"transient_for"`
}
// NodeID is an i3-internal ID for the node, which can be used to identify
// containers within the IPC interface.
type NodeID int64
// Node is a node in a Tree.
//
// See https://i3wm.org/docs/ipc.html#_tree_reply for more details.
type Node struct {
ID NodeID `json:"id"`
Name string `json:"name"` // window: title, container: internal name
Type NodeType `json:"type"`
Border BorderStyle `json:"border"`
CurrentBorderWidth int64 `json:"current_border_width"`
Layout Layout `json:"layout"`
Percent float64 `json:"percent"`
Rect Rect `json:"rect"` // absolute (= relative to X11 display)
WindowRect Rect `json:"window_rect"` // window, relative to Rect
DecoRect Rect `json:"deco_rect"` // decoration, relative to Rect
Geometry Rect `json:"geometry"` // original window geometry, absolute
Window int64 `json:"window"` // X11 window ID of the client window
WindowProperties WindowProperties `json:"window_properties"`
Urgent bool `json:"urgent"` // urgency hint set
Focused bool `json:"focused"`
Focus []NodeID `json:"focus"`
Nodes []*Node `json:"nodes"`
FloatingNodes []*Node `json:"floating_nodes"`
}
// FindChild returns the first Node matching predicate, using pre-order
// depth-first search.
func (n *Node) FindChild(predicate func(*Node) bool) *Node {
if predicate(n) {
return n
}
for _, c := range n.Nodes {
if con := c.FindChild(predicate); con != nil {
return con
}
}
for _, c := range n.FloatingNodes {
if con := c.FindChild(predicate); con != nil {
return con
}
}
return nil
}
// FindFocused returns the first Node matching predicate from the sub-tree of
// directly and indirectly focused containers.
//
// As an example, consider this layout tree (simplified):
//
// root
// │
// HDMI2
// ╱ ╲
// … workspace 1
// ╱ ╲
// XTerm Firefox
//
// In this example, if Firefox is focused, FindFocused will return the first
// container matching predicate of root, HDMI2, workspace 1, Firefox (in this
// order).
func (n *Node) FindFocused(predicate func(*Node) bool) *Node {
if predicate(n) {
return n
}
if len(n.Focus) == 0 {
return nil
}
first := n.Focus[0]
for _, c := range n.Nodes {
if c.ID == first {
return c.FindFocused(predicate)
}
}
for _, c := range n.FloatingNodes {
if c.ID == first {
return c.FindFocused(predicate)
}
}
return nil
}
// Tree is an i3 layout tree, starting with Root.
type Tree struct {
// Root is the root node of the layout tree.
Root *Node
}
// GetTree returns i3’s layout tree.
//
// GetTree is supported in i3 ≥ v4.0 (2011-07-31).
func GetTree() (Tree, error) {
reply, err := roundTrip(messageTypeGetTree, nil)
if err != nil {
return Tree{}, err
}
var root Node
err = json.Unmarshal(reply.Payload, &root)
return Tree{Root: &root}, err
}

16
vendor/go.i3wm.org/i3/validpid.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
package i3
import "syscall"
func pidValid(pid int) bool {
// As per kill(2) from POSIX.1-2008, sending signal 0 validates a pid.
if err := syscall.Kill(pid, 0); err != nil {
if err == syscall.EPERM {
// Process still alive (but no permission to signal):
return true
}
// errno is likely ESRCH (process not found).
return false // Process not alive.
}
return true // Process still alive.
}

62
vendor/go.i3wm.org/i3/version.go generated vendored Normal file
View File

@@ -0,0 +1,62 @@
package i3
import (
"encoding/json"
"fmt"
"log"
)
// Version describes an i3 version.
//
// See https://i3wm.org/docs/ipc.html#_version_reply for more details.
type Version struct {
Major int64 `json:"major"`
Minor int64 `json:"minor"`
Patch int64 `json:"patch"`
Variant string `json:"variant,omitempty"`
HumanReadable string `json:"human_readable"`
LoadedConfigFileName string `json:"loaded_config_file_name"`
}
// GetVersion returns i3’s version.
//
// GetVersion is supported in i3 ≥ v4.3 (2012-09-19).
func GetVersion() (Version, error) {
reply, err := roundTrip(messageTypeGetVersion, nil)
if err != nil {
return Version{}, err
}
var v Version
err = json.Unmarshal(reply.Payload, &v)
return v, err
}
// version is a lazily-initialized, possibly stale copy of i3’s GET_VERSION
// reply. Access only values which don’t change, e.g. Major, Minor.
var version Version
// AtLeast returns nil if i3’s major version matches major and i3’s minor
// version is at least minor or newer. Otherwise, it returns an error message
// stating i3 is too old.
func AtLeast(major int64, minor int64) error {
if major == 0 {
return fmt.Errorf("BUG: major == 0 is non-sensical. Is a lookup table entry missing?")
}
if version.Major == 0 {
var err error
version, err = GetVersion()
if err != nil {
return err
}
}
if version.Variant != "" {
log.Printf("non standard i3 payload variant '%s' detected. Ignoring version check. This is fully unsupported.", version.Variant)
return nil
}
if version.Major == major && version.Minor >= minor {
return nil
}
return fmt.Errorf("i3 version too old: got %d.%d, want ≥ %d.%d", version.Major, version.Minor, major, minor)
}

30
vendor/go.i3wm.org/i3/workspaces.go generated vendored Normal file
View File

@@ -0,0 +1,30 @@
package i3
import "encoding/json"
// Workspace describes an i3 workspace.
//
// See https://i3wm.org/docs/ipc.html#_workspaces_reply for more details.
type Workspace struct {
Num int64 `json:"num"`
Name string `json:"name"`
Visible bool `json:"visible"`
Focused bool `json:"focused"`
Urgent bool `json:"urgent"`
Rect Rect `json:"rect"`
Output string `json:"output"`
}
// GetWorkspaces returns i3’s current workspaces.
//
// GetWorkspaces is supported in i3 ≥ v4.0 (2011-07-31).
func GetWorkspaces() ([]Workspace, error) {
reply, err := roundTrip(messageTypeGetWorkspaces, nil)
if err != nil {
return nil, err
}
var ws []Workspace
err = json.Unmarshal(reply.Payload, &ws)
return ws, err
}