func connect(c *xgb.Conn, s *xproto.ScreenInfo, rl_execute_atom xproto.Atom, args []string) { log.Println("Connecting with args:", args) tree, err := xproto.QueryTree(c, s.Root).Reply() if err != nil { log.Panic("QueryTree failed:", err) } // Broadcast a property request to every window results := make([]xproto.GetPropertyCookie, len(tree.Children)) for ch, child := range tree.Children { results[ch] = xproto.GetProperty(c, false, child, rl_execute_atom, xproto.GetPropertyTypeAny, 0, 1024) } success := false // Get the responses, look for windows that can recieve our command for i, r := range results { reply, err := r.Reply() if err != nil { log.Panic("GetPropertyRequest failed:", err) } if reply.Format != 0 { data := []byte(strings.Join(args, "\x00")) err = xproto.ChangePropertyChecked(c, xproto.PropModeReplace, tree.Children[i], rl_execute_atom, xproto.AtomString, 8, uint32(len(data)), data).Check() log.Println(" .. sent") success = true } } if success != true { log.Println(" .. server not running? atom = ", rl_execute_atom) } }
// currentTime forcefully causes a PropertyNotify event to fire on the root // window, then scans the event queue and picks up the time. // // It is NOT SAFE to call this function in a place other than Wingo's // initialization. Namely, this function subverts xevent's queue and reads // events directly from X. func currentTime(X *xgbutil.XUtil) (xproto.Timestamp, error) { wmClassAtom, err := xprop.Atm(X, "WM_CLASS") if err != nil { return 0, err } stringAtom, err := xprop.Atm(X, "STRING") if err != nil { return 0, err } // Make sure we're listening to PropertyChange events on the root window. err = xwindow.New(X, X.RootWin()).Listen(xproto.EventMaskPropertyChange) if err != nil { return 0, fmt.Errorf( "Could not listen to Root window events (PropertyChange): %s", err) } // Do a zero-length append on a property as suggested by ICCCM 2.1. err = xproto.ChangePropertyChecked( X.Conn(), xproto.PropModeAppend, X.RootWin(), wmClassAtom, stringAtom, 8, 0, nil).Check() if err != nil { return 0, err } // Now look for the PropertyNotify generated by that zero-length append // and return the timestamp attached to that event. // Note that we do this outside of xgbutil/xevent, since ownership // is literally the first thing we do after connecting to X. // (i.e., we don't have our event handling system initialized yet.) timeout := time.After(3 * time.Second) for { select { case <-timeout: return 0, fmt.Errorf( "Expected a PropertyNotify event to get a valid timestamp, " + "but never received one.") default: ev, err := X.Conn().PollForEvent() if err != nil { continue } if propNotify, ok := ev.(xproto.PropertyNotifyEvent); ok { X.TimeSet(propNotify.Time) // why not? return propNotify.Time, nil } time.Sleep(100 * time.Millisecond) } } panic("unreachable") }
func (a *atomic) ChangeProp(w xproto.Window, format byte, prop, typ string, data []byte) error { propAtom, err := a.Atom(prop) if err != nil { return err } typAtom, err := a.Atom(typ) if err != nil { return err } return xproto.ChangePropertyChecked(a.c, xproto.PropModeReplace, w, propAtom, typAtom, format, uint32(len(data)/(int(format)/8)), data).Check() }
func start_server(c *xgb.Conn, s *xproto.ScreenInfo, rl_execute_atom xproto.Atom) { win, err := xproto.NewWindowId(c) if err != nil { panic(err) } // Make a window which can be communicated with err = xproto.CreateWindowChecked(c, s.RootDepth, win, s.Root, 0, 0, 1, 1, 0, 0, 0, 0, nil).Check() if err != nil { panic(err) } err = xproto.ChangePropertyChecked(c, xproto.PropModeReplace, win, rl_execute_atom, xproto.AtomString, 8, xproto.PropModeReplace, []byte("\x00")).Check() if err != nil { panic(err) } err = xproto.ChangeWindowAttributesChecked(c, win, xproto.CwEventMask, []uint32{xproto.EventMaskPropertyChange}).Check() if err != nil { panic(err) } get_execute_value := func() string { response, err := xproto.GetProperty(c, false, win, rl_execute_atom, xproto.GetPropertyTypeAny, 0, 1024).Reply() if err != nil { panic(err) } result := string(response.Value) return result } log.Print("Ready and waiting..") // Event loop for { reply, err := c.WaitForEvent() if err != nil { log.Panic("Error in event loop:", err) } switch event := reply.(type) { case xproto.PropertyNotifyEvent: if event.Window == win && event.Atom == rl_execute_atom { values := strings.Split(get_execute_value(), "\x00") run(values) } } } }
func initXSettings() { a0 := internAtom("_XSETTINGS_S0") if err := xp.SetSelectionOwnerChecked(xConn, desktopXWin, a0, xp.TimeCurrentTime).Check(); err != nil { log.Printf("could not set xsettings: %v", err) return } a1 := internAtom("_XSETTINGS_SETTINGS") encoded := makeEncodedXSettings() if err := xp.ChangePropertyChecked(xConn, xp.PropModeReplace, desktopXWin, a1, a1, 8, uint32(len(encoded)), encoded).Check(); err != nil { log.Printf("could not set xsettings: %v", err) return } }
// ChangeProperty abstracts the semi-nastiness of xgb.ChangeProperty. func ChangeProp(xu *xgbutil.XUtil, win xproto.Window, format byte, prop string, typ string, data []byte) error { propAtom, err := Atm(xu, prop) if err != nil { return err } typAtom, err := Atm(xu, typ) if err != nil { return err } return xproto.ChangePropertyChecked(xu.Conn(), xproto.PropModeReplace, win, propAtom, typAtom, format, uint32(len(data)/(int(format)/8)), data).Check() }