package swayipc import ( "encoding/json" "fmt" "reflect" ) // Event types. const ( EvWorkspace int = 0x80000000 EvOutput int = 0x80000001 EvMode int = 0x80000002 EvWindow int = 0x80000003 EvBarconfigUpdate int = 0x80000004 EvBinding int = 0x80000005 EvShutdown int = 0x80000006 EvTick int = 0x80000007 EvBarStateUpdate int = 0x80000014 EvInput int = 0x80000015 ) // Event is the subscriber struct, use this to tell swayipc which // events you want to subscribe. type Event struct { Workspace bool `json:"workspace"` Output bool `json:"output"` Mode bool `json:"mode"` Window bool `json:"window"` BarconfigUpdate bool `json:"barconfig_update"` Binding bool `json:"binding"` Shutdown bool `json:"shutdown"` Tick bool `json:"tick"` BarStateUpdate bool `json:"bar_state_update"` Input bool `json:"input"` } // EventWorkspace stores a workspace event response type EventWorkspace struct { Change string `json:"change"` Current *Node `json:"workspace"` Old *Node `json:"old"` } // EventOutput stores an output event response type EventOutput struct { Change string `json:"change"` } // EventMode stores a ode event response type EventMode struct { Change string `json:"change"` PangoMarkup *Node `json:"pango_markup"` } // EventWindow stores a window event response type EventWindow struct { Change string `json:"change"` Container *Node `json:"container"` } // EventBarConfig stores a BarConfig event response type EventBarConfig struct { Change string `json:"change"` Binding *Binding `json:"binding"` } // EventShutdown stores a Shutdown event response type EventShutdown struct { Change string `json:"change"` } // EventTick stores a Tick event response type EventTick struct { First bool `json:"first"` Payload string `json:"payload"` } // EventBarState stores a BarState event response type EventBarState struct { ID string `json:"id"` VisibleByModifier bool `json:"visible_by_modifier"` } // EventInput stores an Input event response type EventInput struct { Change string `json:"change"` Input *Input `json:"input"` } // Subscribe allows to subscribe to one or more events. Fill the // Event object accordingly. // // Returns a response list containing a response for every subscribed // event. func (ipc *SwayIPC) Subscribe(sub *Event) ([]*Response, error) { events := eventList(sub) jsonpayload, err := json.Marshal(events) if err != nil { return nil, fmt.Errorf("failed to json marshal event list: %w", err) } err = ipc.sendHeader(MsgSubscribe, uint32(len(jsonpayload))) if err != nil { return nil, err } err = ipc.sendPayload(jsonpayload) if err != nil { return nil, err } payload, err := ipc.readResponse() if err != nil { responses := []*Response{} if err := json.Unmarshal(payload.Payload, &responses); err != nil { return nil, fmt.Errorf("failed to unmarshal json response: %w", err) } return responses, err } // register the subscribed events ipc.Events = sub return nil, nil } // EventLoop starts an event loop. // // Once you have subscribed to an event, you need to enter // an event loop over the same running socket connection. Sway will // send event payloads for every subscribed event whenever it happens. // // You supply the loop a generic callback function, which will be // called every time an event occurs. The function will receive the // swayipc.RawResponse object for the event. You need to Unmarshall the // Payload field yourself. // // If your callback function returns an error, the event loop returns // with this error and finishes thus. func (ipc *SwayIPC) EventLoop(callback func(event *RawResponse) error) error { for { payload, err := ipc.readResponse() if err != nil { return err } if err := callback(payload); err != nil { return err } } } // eventList returns a list of subscribe events based on given Event objectstrucstruc func eventList(sub *Event) []string { out := []string{} subv := reflect.ValueOf(sub).Elem() subType := subv.Type() for i := range subv.NumField() { field := subv.Field(i) structField := subType.Field(i) value := field.Interface() key := structField.Name if tag := structField.Tag.Get(`json`); tag != "" { key = tag } if value.(bool) { out = append(out, key) } } return out }