// WM_HINTS get func WmHintsGet(xu *xgbutil.XUtil, win xproto.Window) (hints *Hints, err error) { lenExpect := 9 raw, err := xprop.PropValNums(xprop.GetProperty(xu, win, "WM_HINTS")) if err != nil { return nil, err } if len(raw) != lenExpect { return nil, fmt.Errorf("WmHints: There are %d fields in "+ "WM_HINTS, but xgbutil expects %d.", len(raw), lenExpect) } hints = &Hints{} hints.Flags = raw[0] hints.Input = raw[1] hints.InitialState = raw[2] hints.IconPixmap = xproto.Pixmap(raw[3]) hints.IconWindow = xproto.Window(raw[4]) hints.IconX = int(raw[5]) hints.IconY = int(raw[6]) hints.IconMask = xproto.Pixmap(raw[7]) hints.WindowGroup = xproto.Window(raw[8]) return hints, nil }
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" query1, buf := xproto.InternAtom(X, nil, true, uint16(len(aname)), aname) activeAtom, err := query1.Reply() if err != nil { log.Fatal(err) } // Get the atom id (i.e., intern an atom) of "_NET_WM_NAME". aname = "_NET_WM_NAME" query2, buf := xproto.InternAtom(X, buf, true, uint16(len(aname)), aname) nameAtom, err := query2.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. query3, buf := xproto.GetProperty(X, buf, false, root, activeAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1) reply, err := query3.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. query4, buf := xproto.GetProperty(X, buf, false, windowId, nameAtom.Atom, xproto.GetPropertyTypeAny, 0, (1<<32)-1) reply, err = query4.Reply() if err != nil { log.Fatal(err) } fmt.Printf("Active window name: %s\n", string(reply.Value)) }
// PropValWindow transforms a GetPropertyReply struct into an X resource // window identifier. // The property reply must be in 32 bit format. func PropValWindow(reply *xproto.GetPropertyReply, err error) (xproto.Window, error) { if err != nil { return 0, err } if reply.Format != 32 { return 0, fmt.Errorf("PropValId: Expected format 32 but got %d", reply.Format) } return xproto.Window(xgb.Get32(reply.Value)), nil }
// WM_STATE get func WmStateGet(xu *xgbutil.XUtil, win xproto.Window) (*WmState, error) { raw, err := xprop.PropValNums(xprop.GetProperty(xu, win, "WM_STATE")) if err != nil { return nil, err } if len(raw) != 2 { return nil, fmt.Errorf("WmState: Expected two integers in WM_STATE property "+ "but xgbutil found %d in '%v'.", len(raw), raw) } return &WmState{ State: raw[0], Icon: xproto.Window(raw[1]), }, nil }
// getOverlayWindowReply reads a byte slice into a GetOverlayWindowReply value. func getOverlayWindowReply(buf []byte) *GetOverlayWindowReply { v := new(GetOverlayWindowReply) b := 1 // skip reply determinant b += 1 // padding v.Sequence = xgb.Get16(buf[b:]) b += 2 v.Length = xgb.Get32(buf[b:]) // 4-byte units b += 4 v.OverlayWin = xproto.Window(xgb.Get32(buf[b:])) b += 4 b += 20 // padding return v }
// PropValWindows is the same as PropValWindow, except that it returns a slice // of identifiers. Also must be 32 bit format. func PropValWindows(reply *xproto.GetPropertyReply, err error) ([]xproto.Window, error) { if err != nil { return nil, err } if reply.Format != 32 { return nil, fmt.Errorf("PropValIds: Expected format 32 but got %d", reply.Format) } ids := make([]xproto.Window, reply.ValueLen) vals := reply.Value for i := 0; len(vals) >= 4; i++ { ids[i] = xproto.Window(xgb.Get32(vals)) vals = vals[4:] } return ids, nil }
// NotifyEventNew constructs a NotifyEvent value that implements xgb.Event from a byte slice. func NotifyEventNew(buf []byte) xgb.Event { v := NotifyEvent{} b := 1 // don't read event number v.ShapeKind = Kind(buf[b]) b += 1 v.Sequence = xgb.Get16(buf[b:]) b += 2 v.AffectedWindow = xproto.Window(xgb.Get32(buf[b:])) b += 4 v.ExtentsX = int16(xgb.Get16(buf[b:])) b += 2 v.ExtentsY = int16(xgb.Get16(buf[b:])) b += 2 v.ExtentsWidth = xgb.Get16(buf[b:]) b += 2 v.ExtentsHeight = xgb.Get16(buf[b:]) b += 2 v.ServerTime = xproto.Timestamp(xgb.Get32(buf[b:])) b += 4 if buf[b] == 1 { v.Shaped = true } else { v.Shaped = false } b += 1 b += 11 // padding return v }
// processEventQueue processes every item in the event/error queue. func processEventQueue(xu *xgbutil.XUtil, pingBefore, pingAfter chan struct{}) { for !Empty(xu) { if Quitting(xu) { return } // We send the ping *before* the next event is dequeued. // This is so the queue doesn't present a misrepresentation of which // events haven't been processed yet. if pingBefore != nil && pingAfter != nil { pingBefore <- struct{}{} } ev, err := Dequeue(xu) // If we gobbled up an error, send it to the error event handler // and move on the next event/error. if err != nil { ErrorHandlerGet(xu)(err) if pingBefore != nil && pingAfter != nil { pingAfter <- struct{}{} } continue } // We know there isn't an error. If there isn't an event either, // then there's a bug somewhere. if ev == nil { xgbutil.Logger.Fatal("BUG: Expected an event but got nil.") } switch event := ev.(type) { case xproto.KeyPressEvent: e := KeyPressEvent{&event} // If we're redirecting key events, this is the place to do it! if wid := RedirectKeyGet(xu); wid > 0 { e.Event = wid } xu.TimeSet(e.Time) runCallbacks(xu, e, KeyPress, e.Event) case xproto.KeyReleaseEvent: e := KeyReleaseEvent{&event} // If we're redirecting key events, this is the place to do it! if wid := RedirectKeyGet(xu); wid > 0 { e.Event = wid } xu.TimeSet(e.Time) runCallbacks(xu, e, KeyRelease, e.Event) case xproto.ButtonPressEvent: e := ButtonPressEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, ButtonPress, e.Event) case xproto.ButtonReleaseEvent: e := ButtonReleaseEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, ButtonRelease, e.Event) case xproto.MotionNotifyEvent: e := MotionNotifyEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, MotionNotify, e.Event) case xproto.EnterNotifyEvent: e := EnterNotifyEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, EnterNotify, e.Event) case xproto.LeaveNotifyEvent: e := LeaveNotifyEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, LeaveNotify, e.Event) case xproto.FocusInEvent: e := FocusInEvent{&event} runCallbacks(xu, e, FocusIn, e.Event) case xproto.FocusOutEvent: e := FocusOutEvent{&event} runCallbacks(xu, e, FocusOut, e.Event) case xproto.KeymapNotifyEvent: e := KeymapNotifyEvent{&event} runCallbacks(xu, e, KeymapNotify, NoWindow) case xproto.ExposeEvent: e := ExposeEvent{&event} runCallbacks(xu, e, Expose, e.Window) case xproto.GraphicsExposureEvent: e := GraphicsExposureEvent{&event} runCallbacks(xu, e, GraphicsExposure, xproto.Window(e.Drawable)) case xproto.NoExposureEvent: e := NoExposureEvent{&event} runCallbacks(xu, e, NoExposure, xproto.Window(e.Drawable)) case xproto.VisibilityNotifyEvent: e := VisibilityNotifyEvent{&event} runCallbacks(xu, e, VisibilityNotify, e.Window) case xproto.CreateNotifyEvent: e := CreateNotifyEvent{&event} runCallbacks(xu, e, CreateNotify, e.Parent) case xproto.DestroyNotifyEvent: e := DestroyNotifyEvent{&event} runCallbacks(xu, e, DestroyNotify, e.Window) case xproto.UnmapNotifyEvent: e := UnmapNotifyEvent{&event} runCallbacks(xu, e, UnmapNotify, e.Window) case xproto.MapNotifyEvent: e := MapNotifyEvent{&event} runCallbacks(xu, e, MapNotify, e.Event) case xproto.MapRequestEvent: e := MapRequestEvent{&event} runCallbacks(xu, e, MapRequest, e.Window) runCallbacks(xu, e, MapRequest, e.Parent) case xproto.ReparentNotifyEvent: e := ReparentNotifyEvent{&event} runCallbacks(xu, e, ReparentNotify, e.Window) case xproto.ConfigureNotifyEvent: e := ConfigureNotifyEvent{&event} runCallbacks(xu, e, ConfigureNotify, e.Window) case xproto.ConfigureRequestEvent: e := ConfigureRequestEvent{&event} runCallbacks(xu, e, ConfigureRequest, e.Window) runCallbacks(xu, e, ConfigureRequest, e.Parent) case xproto.GravityNotifyEvent: e := GravityNotifyEvent{&event} runCallbacks(xu, e, GravityNotify, e.Window) case xproto.ResizeRequestEvent: e := ResizeRequestEvent{&event} runCallbacks(xu, e, ResizeRequest, e.Window) case xproto.CirculateNotifyEvent: e := CirculateNotifyEvent{&event} runCallbacks(xu, e, CirculateNotify, e.Window) case xproto.CirculateRequestEvent: e := CirculateRequestEvent{&event} runCallbacks(xu, e, CirculateRequest, e.Window) case xproto.PropertyNotifyEvent: e := PropertyNotifyEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, PropertyNotify, e.Window) case xproto.SelectionClearEvent: e := SelectionClearEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, SelectionClear, e.Owner) case xproto.SelectionRequestEvent: e := SelectionRequestEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, SelectionRequest, e.Requestor) case xproto.SelectionNotifyEvent: e := SelectionNotifyEvent{&event} xu.TimeSet(e.Time) runCallbacks(xu, e, SelectionNotify, e.Requestor) case xproto.ColormapNotifyEvent: e := ColormapNotifyEvent{&event} runCallbacks(xu, e, ColormapNotify, e.Window) case xproto.ClientMessageEvent: e := ClientMessageEvent{&event} runCallbacks(xu, e, ClientMessage, e.Window) case xproto.MappingNotifyEvent: e := MappingNotifyEvent{&event} runCallbacks(xu, e, MappingNotify, NoWindow) case shape.NotifyEvent: e := ShapeNotifyEvent{&event} runCallbacks(xu, e, ShapeNotify, e.AffectedWindow) default: if event != nil { xgbutil.Logger.Printf("ERROR: UNSUPPORTED EVENT TYPE: %T", event) } } if pingBefore != nil && pingAfter != nil { pingAfter <- struct{}{} } } }