func main() { X, err := xgb.NewConn() if err != nil { log.Fatal(err) } // Get the window id of the root window. setup := xproto.Setup(X) root := setup.DefaultScreen(X).Root // Get the atom id (i.e., intern an atom) of "_NET_ACTIVE_WINDOW". aname := "_NET_ACTIVE_WINDOW" activeAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), aname).Reply() if err != nil { log.Fatal(err) } // Get the atom id (i.e., intern an atom) of "_NET_WM_NAME". aname = "_NET_WM_NAME" nameAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), aname).Reply() if err != nil { log.Fatal(err) } // Get the actual value of _NET_ACTIVE_WINDOW. // Note that 'reply.Value' is just a slice of bytes, so we use an // XGB helper function, 'Get32', to pull an unsigned 32-bit integer out // of the byte slice. We then convert it to an X resource id so it can // be used to get the name of the window in the next GetProperty request. reply, err := xproto.GetProperty(X, false, root, activeAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { log.Fatal(err) } windowId := xproto.Window(xgb.Get32(reply.Value)) fmt.Printf("Active window id: %X\n", windowId) // Now get the value of _NET_WM_NAME for the active window. // Note that this time, we simply convert the resulting byte slice, // reply.Value, to a string. reply, err = xproto.GetProperty(X, false, windowId, nameAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { log.Fatal(err) } fmt.Printf("Active window name: %s\n", string(reply.Value)) }
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) } }
func (w *window) property(a xp.Atom) string { p, err := xp.GetProperty(xConn, false, w.xWin, a, xp.GetPropertyTypeAny, 0, 1<<32-1).Reply() if err != nil { log.Println(err) } if p == nil { return "" } return string(p.Value) }
func (logger *WindowLogger) getCurWindowTitle() (name string, err error) { // Get the window id of the root window. setup := xproto.Setup(logger.X11Connection) root := setup.DefaultScreen(logger.X11Connection).Root // Get the atom id (i.e., intern an atom) of "_NET_ACTIVE_WINDOW". aname := "_NET_ACTIVE_WINDOW" activeAtom, err := xproto.InternAtom(logger.X11Connection, true, uint16(len(aname)), aname).Reply() if err != nil { return "", err } // Get the atom id (i.e., intern an atom) of "_NET_WM_NAME". aname = "_NET_WM_NAME" nameAtom, err := xproto.InternAtom(logger.X11Connection, true, uint16(len(aname)), aname).Reply() if err != nil { return "", err } // Get the actual value of _NET_ACTIVE_WINDOW. // Note that 'reply.Value' is just a slice of bytes, so we use an // XGB helper function, 'Get32', to pull an unsigned 32-bit integer out // of the byte slice. We then convert it to an X resource id so it can // be used to get the name of the window in the next GetProperty request. reply, err := xproto.GetProperty(logger.X11Connection, false, root, activeAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { return "", err } windowId := xproto.Window(xgb.Get32(reply.Value)) // Now get the value of _NET_WM_NAME for the active window. // Note that this time, we simply convert the resulting byte slice, // reply.Value, to a string. reply, err = xproto.GetProperty(logger.X11Connection, false, windowId, nameAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { return "", err } return string(reply.Value), nil }
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 (a *atomic) GetProp(w xproto.Window, s string) (*xproto.GetPropertyReply, error) { atomId, err := a.Atom(s) if err != nil { return nil, err } reply, err := xproto.GetProperty(a.c, false, w, atomId, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { msg := fmt.Sprintf("Error retrieving property '%s' on window %x: %s", s, w, err) return nil, GetPropertyError(msg) } if reply.Format == 0 { msg := fmt.Sprintf("No such property '%s' on window %x", s, w) return nil, GetPropertyError(msg) } return reply, nil }
// GetProperty abstracts the messiness of calling xgb.GetProperty. func GetProperty(xu *xgbutil.XUtil, win xproto.Window, atom string) ( *xproto.GetPropertyReply, error) { atomId, err := Atm(xu, atom) if err != nil { return nil, err } reply, err := xproto.GetProperty(xu.Conn(), false, win, atomId, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { return nil, fmt.Errorf("GetProperty: Error retrieving property '%s' "+ "on window %x: %s", atom, win, err) } if reply.Format == 0 { return nil, fmt.Errorf("GetProperty: No such property '%s' on "+ "window %x.", atom, win) } return reply, nil }
// Listen ... func Listen(fn func(e Event)) error { X, err := xgb.NewConn() if err != nil { log.Fatal(err) } setup := xproto.Setup(X) root := setup.DefaultScreen(X).Root var prevWindowID xproto.Window var prevClasses []string for { <-time.After(msRefresh * time.Millisecond) // From one of the xgb examples. aname := "_NET_ACTIVE_WINDOW" activeAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), aname).Reply() if err != nil { log.Println(err) continue } reply, err := xproto.GetProperty(X, false, root, activeAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { log.Println(err) continue } windowID := xproto.Window(xgb.Get32(reply.Value)) aname = "WM_CLASS" nameAtom, err := xproto.InternAtom(X, true, uint16(len(aname)), aname).Reply() if err != nil { log.Println(err) continue } reply, err = xproto.GetProperty(X, false, windowID, nameAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1).Reply() if err != nil { log.Println(err) continue } classes := stringSlice(reply.Value) // Check if active window has changed since last time. if windowID != prevWindowID { fn(Lost{ WMClass: prevClasses, }) fn(Gained{ WMClass: classes, }) prevWindowID = windowID prevClasses = classes } } }
func manage(xWin xp.Window, mapRequest bool) { callFocus := false w := findWindow(func(w *window) bool { return w.xWin == xWin }) if w == nil { wmDeleteWindow, wmTakeFocus := false, false if prop, err := xp.GetProperty(xConn, false, xWin, atomWMProtocols, xp.GetPropertyTypeAny, 0, 64).Reply(); err != nil { log.Println(err) } else if prop != nil { for v := prop.Value; len(v) >= 4; v = v[4:] { switch xp.Atom(u32(v)) { case atomWMDeleteWindow: wmDeleteWindow = true case atomWMTakeFocus: wmTakeFocus = true } } } transientFor := (*window)(nil) if prop, err := xp.GetProperty(xConn, false, xWin, atomWMTransientFor, xp.GetPropertyTypeAny, 0, 64).Reply(); err != nil { log.Println(err) } else if prop != nil { if v := prop.Value; len(v) == 4 { transientForXWin := xp.Window(u32(v)) transientFor = findWindow(func(w *window) bool { return w.xWin == transientForXWin }) } } k := screens[0].workspace if p, err := xp.QueryPointer(xConn, rootXWin).Reply(); err != nil { log.Println(err) } else if p != nil { k = screenContaining(p.RootX, p.RootY).workspace } w = &window{ transientFor: transientFor, xWin: xWin, rect: xp.Rectangle{ X: offscreenXY, Y: offscreenXY, Width: 1, Height: 1, }, wmDeleteWindow: wmDeleteWindow, wmTakeFocus: wmTakeFocus, } f := k.focusedFrame previous := k.dummyWindow.link[prev] if transientFor != nil { previous = transientFor } else if f.window != nil { previous = f.window } w.link[next] = previous.link[next] w.link[prev] = previous w.link[next].link[prev] = w w.link[prev].link[next] = w if transientFor != nil && transientFor.frame != nil { f = transientFor.frame f.window, transientFor.frame = nil, nil } else if f.window != nil { f = k.mainFrame.firstEmptyFrame() } if f != nil { f.window, w.frame = w, f callFocus = f == k.focusedFrame } else { pulseChan <- time.Now() } check(xp.ChangeWindowAttributesChecked(xConn, xWin, xp.CwEventMask, []uint32{xp.EventMaskEnterWindow | xp.EventMaskStructureNotify}, )) w.configure() if transientFor != nil { transientFor.hasTransientFor = true transientFor.configure() } } if mapRequest { check(xp.MapWindowChecked(xConn, xWin)) } if callFocus { focus(w) } makeLists() pulseChan <- time.Now() }