// _NET_DESKTOP_LAYOUT set func DesktopLayoutSet(xu *xgbutil.XUtil, orientation, columns, rows, startingCorner uint) error { return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_DESKTOP_LAYOUT", "CARDINAL", orientation, columns, rows, startingCorner) }
// sendClientMessages is a goroutine that sends client messages to the root // window. We then listen to them later as a demonstration of responding to // X events. (They are sent with SubstructureNotify and SubstructureRedirect // masks set. So in order to receive them, we'll have to explicitly listen // to events of that type on the root window.) func xSource(X *xgbutil.XUtil) { i := 1 for { ewmh.ClientEvent(X, X.RootWin(), "NOOP", i) i++ time.Sleep(200 * time.Millisecond) } }
// _NET_SUPPORTED set // This will create any atoms in the argument if they don't already exist. func SupportedSet(xu *xgbutil.XUtil, atomNames []string) error { atoms, err := xprop.StrToAtoms(xu, atomNames) if err != nil { return err } return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_SUPPORTED", "ATOM", atoms...) }
// _NET_SHOWING_DESKTOP req func ShowingDesktopReq(xu *xgbutil.XUtil, show bool) error { var showInt uint if show { showInt = 1 } else { showInt = 0 } return ClientEvent(xu, xu.RootWin(), "_NET_SHOWING_DESKTOP", showInt) }
// _NET_DESKTOP_GEOMETRY get func DesktopGeometryGet(xu *xgbutil.XUtil) (*DesktopGeometry, error) { geom, err := xprop.PropValNums(xprop.GetProperty(xu, xu.RootWin(), "_NET_DESKTOP_GEOMETRY")) if err != nil { return nil, err } return &DesktopGeometry{Width: int(geom[0]), Height: int(geom[1])}, nil }
// _NET_DESKTOP_NAMES set func DesktopNamesSet(xu *xgbutil.XUtil, names []string) error { nullterm := make([]byte, 0) for _, name := range names { nullterm = append(nullterm, name...) nullterm = append(nullterm, 0) } return xprop.ChangeProp(xu, xu.RootWin(), 8, "_NET_DESKTOP_NAMES", "UTF8_STRING", nullterm) }
// _NET_SHOWING_DESKTOP set func ShowingDesktopSet(xu *xgbutil.XUtil, show bool) error { var showInt uint if show { showInt = 1 } else { showInt = 0 } return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_SHOWING_DESKTOP", "CARDINAL", showInt) }
// _NET_WM_HANDLED_ICONS set func WmHandledIconsSet(xu *xgbutil.XUtil, handle bool) error { var handled uint if handle { handled = 1 } else { handled = 0 } return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_WM_HANDLED_ICONS", "CARDINAL", handled) }
// _NET_DESKTOP_VIEWPORT set func DesktopViewportSet(xu *xgbutil.XUtil, viewports []DesktopViewport) error { coords := make([]uint, len(viewports)*2) for i, viewport := range viewports { coords[i*2] = uint(viewport.X) coords[i*2+1] = uint(viewport.Y) } return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_DESKTOP_VIEWPORT", "CARDINAL", coords...) }
// newWindow creates a new window with a random background color. It sets the // WM_PROTOCOLS property to contain the WM_DELETE_WINDOW atom. It also sets // up a ClientMessage event handler so that we know when to destroy the window. // We also set up a mouse binding so that clicking inside a window will // create another one. func newWindow(X *xgbutil.XUtil) { counter++ win, err := xwindow.Generate(X) if err != nil { log.Fatal(err) } // Get a random background color, create the window (ask to receive button // release events while we're at it) and map the window. bgColor := rand.Intn(0xffffff + 1) win.Create(X.RootWin(), 0, 0, 200, 200, xproto.CwBackPixel|xproto.CwEventMask, uint32(bgColor), xproto.EventMaskButtonRelease) // WMGracefulClose does all of the work for us. It sets the appropriate // values for WM_PROTOCOLS, and listens for ClientMessages that implement // the WM_DELETE_WINDOW protocol. When one is found, the provided callback // is executed. win.WMGracefulClose( func(w *xwindow.Window) { // Detach all event handlers. // This should always be done when a window can no longer // receive events. xevent.Detach(w.X, w.Id) mousebind.Detach(w.X, w.Id) w.Destroy() // Exit if there are no more windows left. counter-- if counter == 0 { os.Exit(0) } }) // It's important that the map comes after setting WMGracefulClose, since // the WM isn't obliged to watch updates to the WM_PROTOCOLS property. win.Map() // A mouse binding so that a left click will spawn a new window. // Note that we don't issue a grab here. Typically, window managers will // grab a button press on the client window (which usually activates the // window), so that we'd end up competing with the window manager if we // tried to grab it. // Instead, we set a ButtonRelease mask when creating the window and attach // a mouse binding *without* a grab. err = mousebind.ButtonReleaseFun( func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) { newWindow(X) }).Connect(X, win.Id, "1", false, false) if err != nil { log.Fatal(err) } }
// _NET_WORKAREA set func WorkareaSet(xu *xgbutil.XUtil, workareas []Workarea) error { rects := make([]uint, len(workareas)*4) for i, workarea := range workareas { rects[i*4+0] = uint(workarea.X) rects[i*4+1] = uint(workarea.Y) rects[i*4+2] = workarea.Width rects[i*4+3] = workarea.Height } return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_WORKAREA", "CARDINAL", rects...) }
// _NET_SHOWING_DESKTOP get func ShowingDesktopGet(xu *xgbutil.XUtil) (bool, error) { reply, err := xprop.GetProperty(xu, xu.RootWin(), "_NET_SHOWING_DESKTOP") if err != nil { return false, err } val, err := xprop.PropValNum(reply, nil) if err != nil { return false, err } return val == 1, nil }
// newWindow creates a new window that listens to MotionNotify events with // the given backgroundcolor. func newWindow(X *xgbutil.XUtil, color uint32) *xwindow.Window { win, err := xwindow.Generate(X) if err != nil { log.Fatal(err) } err = win.CreateChecked(X.RootWin(), 0, 0, 400, 400, xproto.CwBackPixel|xproto.CwEventMask, color, xproto.EventMaskPointerMotion) if err != nil { log.Fatal(err) } win.Map() return win }
// _NET_DESKTOP_VIEWPORT get func DesktopViewportGet(xu *xgbutil.XUtil) ([]DesktopViewport, error) { coords, err := xprop.PropValNums(xprop.GetProperty(xu, xu.RootWin(), "_NET_DESKTOP_VIEWPORT")) if err != nil { return nil, err } viewports := make([]DesktopViewport, len(coords)/2) for i, _ := range viewports { viewports[i] = DesktopViewport{ X: int(coords[i*2]), Y: int(coords[i*2+1]), } } return viewports, nil }
// dragGrab is a shortcut for grabbing the pointer for a drag. func dragGrab(xu *xgbutil.XUtil, grabwin xproto.Window, win xproto.Window, cursor xproto.Cursor) bool { status, err := GrabPointer(xu, grabwin, xu.RootWin(), cursor) if err != nil { xgbutil.Logger.Printf("Mouse dragging was unsuccessful because: %v", err) return false } if !status { xgbutil.Logger.Println("Mouse dragging was unsuccessful because " + "we could not establish a pointer grab.") return false } mouseDragSet(xu, true) return true }
// _NET_WM_PING req extra func WmPingExtra(xu *xgbutil.XUtil, win xproto.Window, response bool, time xproto.Timestamp) error { pingAtom, err := xprop.Atm(xu, "_NET_WM_PING") if err != nil { return err } var evWindow xproto.Window if response { evWindow = xu.RootWin() } else { evWindow = win } return ClientEvent(xu, evWindow, "WM_PROTOCOLS", int(pingAtom), int(time), int(win)) }
// _NET_WORKAREA get func WorkareaGet(xu *xgbutil.XUtil) ([]Workarea, error) { rects, err := xprop.PropValNums(xprop.GetProperty(xu, xu.RootWin(), "_NET_WORKAREA")) if err != nil { return nil, err } workareas := make([]Workarea, len(rects)/4) for i, _ := range workareas { workareas[i] = Workarea{ X: int(rects[i*4]), Y: int(rects[i*4+1]), Width: rects[i*4+2], Height: rects[i*4+3], } } return workareas, nil }
// _NET_DESKTOP_LAYOUT get func DesktopLayoutGet(xu *xgbutil.XUtil) (dl *DesktopLayout, err error) { dlraw, err := xprop.PropValNums(xprop.GetProperty(xu, xu.RootWin(), "_NET_DESKTOP_LAYOUT")) if err != nil { return nil, err } dl = &DesktopLayout{} dl.Orientation = int(dlraw[0]) dl.Columns = int(dlraw[1]) dl.Rows = int(dlraw[2]) if len(dlraw) > 3 { dl.StartingCorner = int(dlraw[3]) } else { dl.StartingCorner = TopLeft } return dl, nil }
// GetEwmhWM uses the EWMH spec to find if a conforming window manager // is currently running or not. If it is, then its name will be returned. // Otherwise, an error will be returned explaining why one couldn't be found. func GetEwmhWM(xu *xgbutil.XUtil) (string, error) { childCheck, err := SupportingWmCheckGet(xu, xu.RootWin()) if err != nil { return "", fmt.Errorf("GetEwmhWM: Failed because: %s", err) } childCheck2, err := SupportingWmCheckGet(xu, childCheck) if err != nil { return "", fmt.Errorf("GetEwmhWM: Failed because: %s", err) } if childCheck != childCheck2 { return "", fmt.Errorf( "GetEwmhWM: _NET_SUPPORTING_WM_CHECK value on the root window "+ "(%x) does not match _NET_SUPPORTING_WM_CHECK value "+ "on the child window (%x).", childCheck, childCheck2) } return WmNameGet(xu, childCheck) }
// _NET_ACTIVE_WINDOW set func ActiveWindowSet(xu *xgbutil.XUtil, win xproto.Window) error { return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_ACTIVE_WINDOW", "WINDOW", uint(win)) }
// _NET_VIRTUAL_ROOTS get func VirtualRootsGet(xu *xgbutil.XUtil) ([]xproto.Window, error) { return xprop.PropValWindows(xprop.GetProperty(xu, xu.RootWin(), "_NET_VIRTUAL_ROOTS")) }
// _NET_VISIBLE_DESKTOPS get // This is not part of the EWMH spec, but is a property of my own creation. // It allows the window manager to report that it has multiple desktops // viewable at the same time. (This conflicts with other EWMH properties, // so I don't think this will ever be added to the official spec.) func VisibleDesktopsGet(xu *xgbutil.XUtil) ([]uint, error) { return xprop.PropValNums(xprop.GetProperty(xu, xu.RootWin(), "_NET_VISIBLE_DESKTOPS")) }
// _NET_SUPPORTED get func SupportedGet(xu *xgbutil.XUtil) ([]string, error) { reply, err := xprop.GetProperty(xu, xu.RootWin(), "_NET_SUPPORTED") return xprop.PropValAtoms(xu, reply, err) }
// _NET_CURRENT_DESKTOP set func CurrentDesktopSet(xu *xgbutil.XUtil, desk uint) error { return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_CURRENT_DESKTOP", "CARDINAL", desk) }
// _NET_CURRENT_DESKTOP get func CurrentDesktopGet(xu *xgbutil.XUtil) (uint, error) { return xprop.PropValNum(xprop.GetProperty(xu, xu.RootWin(), "_NET_CURRENT_DESKTOP")) }
// _NET_VISIBLE_DESKTOPS set func VisibleDesktopsSet(xu *xgbutil.XUtil, desktops []uint) error { return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_VISIBLE_DESKTOPS", "CARDINAL", desktops...) }
// _NET_CLIENT_LIST_STACKING set func ClientListStackingSet(xu *xgbutil.XUtil, wins []xproto.Window) error { return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_CLIENT_LIST_STACKING", "WINDOW", xprop.WindowToInt(wins)...) }
// _NET_CLIENT_LIST_STACKING get func ClientListStackingGet(xu *xgbutil.XUtil) ([]xproto.Window, error) { return xprop.PropValWindows(xprop.GetProperty(xu, xu.RootWin(), "_NET_CLIENT_LIST_STACKING")) }
// SendRootEvent takes a type implementing the xgb.Event interface, converts it // to raw X bytes, and sends it to the root window using the SendEvent request. func SendRootEvent(xu *xgbutil.XUtil, ev xgb.Event, evMask uint32) error { query, _ := xproto.SendEventChecked(xu.Conn(), nil, false, xu.RootWin(), evMask, string(ev.Bytes())) return query.Check() }
// _NET_VIRTUAL_ROOTS set func VirtualRootsSet(xu *xgbutil.XUtil, wins []xproto.Window) error { return xprop.ChangeProp32(xu, xu.RootWin(), "_NET_VIRTUAL_ROOTS", "WINDOW", xprop.WindowToInt(wins)...) }