// IsFocusProtocol checks whether a ClientMessage event satisfies the // WM_TAKE_FOCUS protocol. func IsFocusProtocol(X *xgbutil.XUtil, ev xevent.ClientMessageEvent) bool { // Make sure the Format is 32. (Meaning that each data item is // 32 bits.) if ev.Format != 32 { return false } // Check to make sure the Type atom is WM_PROTOCOLS. typeName, err := xprop.AtomName(X, ev.Type) if err != nil || typeName != "WM_PROTOCOLS" { // not what we want return false } // Check to make sure the first data item is WM_TAKE_FOCUS. protocolType, err := xprop.AtomName(X, xproto.Atom(ev.Data.Data32[0])) if err != nil || protocolType != "WM_TAKE_FOCUS" { return false } return true }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Start generating other source events. otherChan := otherSource() // Start generating X events (by sending client messages to root window). go xSource(X) // Listen to those X events. xwindow.New(X, X.RootWin()).Listen(xproto.EventMaskSubstructureNotify) // Respond to those X events. xevent.ClientMessageFun( func(X *xgbutil.XUtil, ev xevent.ClientMessageEvent) { atmName, err := xprop.AtomName(X, ev.Type) if err != nil { log.Fatal(err) } fmt.Printf("ClientMessage: %d. %s\n", ev.Data.Data32[0], atmName) }).Connect(X, X.RootWin()) // Instead of using the usual xevent.Main, we use xevent.MainPing. // It runs the main event loop inside a goroutine and returns ping // channels, which are sent benign values right before an event is // dequeued and right after that event has finished running all callbacks // associated with it, respectively. pingBefore, pingAfter, pingQuit := xevent.MainPing(X) for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case otherVal := <-otherChan: fmt.Printf("Processing other event: %d\n", otherVal) case <-pingQuit: fmt.Printf("xevent loop has quit") return } } }