// Refreshes the internal cache of properties. // // NOTE: you do not have to call this, unless you want a more up-to-date value // set than when you first created it with New -- or the last Refresh call. func (xs *XSettings) Refresh() error { xs.props = make(map[string]*XSetting) gso := xproto.GetSelectionOwner(xs.X.Conn(), atomXSettings) reply, err := gso.Reply() if err != nil { return err } prop, err := xprop.GetProperty(xs.X, reply.Owner, "_XSETTINGS_SETTINGS") if err != nil { return err } data := bytes.NewReader(prop.Value) var endian binary.ByteOrder var tmp byte if tmp, err = data.ReadByte(); err != nil { return err } if tmp == 0 { endian = binary.LittleEndian } else { endian = binary.BigEndian } buff := make([]byte, 3, 3) if n, err := data.Read(buff); n != 3 || err != nil { return err } if err = binary.Read(data, endian, &xs.Serial); err != nil { return err } var num uint32 if err = binary.Read(data, endian, &num); err != nil { return err } for i := uint32(0); i < num; i++ { setting, name, err := xs.readSetting(data, endian) if err != nil { return err } xs.props[name] = setting } return nil }
// own requests ownership over the role of window manager in the current // X environment. It can fail if it does not successfully get ownership. // // When 'replace' is true, Wingo will attempt to replace an window manager // that is currently running. Otherwise, Wingo will quit if a window manager // is running. func own(X *xgbutil.XUtil, replace bool) error { otherWmRunning := false otherWmName := "" otherWmOwner := xproto.Window(xproto.WindowNone) xTime, err := currentTime(X) if err != nil { return err } selAtom, err := managerAtom(X) if err != nil { return err } // Check to see if we need to replace. If so, determine whether to // continue based on `replace`. reply, err := xproto.GetSelectionOwner(X.Conn(), selAtom).Reply() if err != nil { return err } if reply.Owner != xproto.WindowNone { otherWmRunning = true otherWmOwner = reply.Owner // Look for the window manager's name for a nicer error message. otherWmName, err = ewmh.GetEwmhWM(X) if err != nil || len(otherWmName) == 0 { otherWmName = "Unknown" } // We need to listen for DestroyNotify events on the selection // owner in case we need to replace the WM. owner := xwindow.New(X, reply.Owner) if err = owner.Listen(xproto.EventMaskStructureNotify); err != nil { return err } } if otherWmRunning { if !replace { return fmt.Errorf( "Another window manager (%s) is already running. Please use "+ "the '--replace' option to replace the current window "+ "manager with Wingo.", otherWmName) } else { logger.Message.Printf( "Waiting for %s to shutdown and transfer ownership to us.", otherWmName) } } logger.Message.Printf("Setting selection owner...") err = xproto.SetSelectionOwnerChecked( X.Conn(), X.Dummy(), selAtom, xTime).Check() if err != nil { return err } // Now we've got to make sure that we *actually* got ownership. logger.Message.Printf("Getting selection owner...") reply, err = xproto.GetSelectionOwner(X.Conn(), selAtom).Reply() if err != nil { return err } if reply.Owner != X.Dummy() { return fmt.Errorf( "Could not acquire ownership with SetSelectionOwner. "+ "GetSelectionOwner claims that '%d' is the owner, but '%d' "+ "needs to be.", reply.Owner, X.Dummy()) } // While X now acknowledges us as the selection owner, it's possible // that the window manager is misbehaving. ICCCM 2.8 calls for the previous // manager to destroy the selection owner when it's OK for us to take // over. Otherwise, listening to SubstructureRedirect on the root window // might fail if we move too quickly. timeout := time.After(3 * time.Second) if otherWmRunning { OTHER_WM_SHUTDOWN: for { select { case <-timeout: return fmt.Errorf( "Wingo failed to replace the currently running window "+ "manager (%s). Namely, Wingo was not able to detect "+ "that the current window manager had shut down.", otherWmName) default: logger.Message.Printf("Polling for event...") ev, err := X.Conn().PollForEvent() if err != nil { continue } logger.Message.Printf("Got event, error: %s -- %s", ev, err) if destNotify, ok := ev.(xproto.DestroyNotifyEvent); ok { if destNotify.Window == otherWmOwner { break OTHER_WM_SHUTDOWN } } time.Sleep(100 * time.Millisecond) } } } logger.Message.Println("Wingo has window manager ownership!") announce(X) // Listen for SelectionClear events. When we get one of these, then we // know a window manager is trying to replace us. xevent.SelectionClearFun(disown).Connect(X, X.Dummy()) return nil }
func New(X *xgbutil.XUtil) (*SystemTray, error) { tray := &SystemTray{ X: X, } var err error if sysTrayAtom == 0 { sysTrayAtom, err = xprop.Atom(X, "_NET_SYSTEM_TRAY_S0", false) if err != nil { return nil, err } } if sysTrayMsgAtom == 0 { sysTrayMsgAtom, err = xprop.Atom(X, "_NET_SYSTEM_TRAY_OPCODE", false) if err != nil { return nil, err } } if managerEventAtom == 0 { managerEventAtom, err = xprop.Atom(X, "MANAGER", false) if err != nil { return nil, err } } tray.wid, err = xwindow.Create(X, X.RootWin()) if err != nil { return nil, err } ts, err := currentTime(X) if err != nil { return nil, err } X.TimeSet(ts) // tray.wid.Listen(xproto.EventMaskNoEvent | xproto.EventMaskPropertyChange) err = xproto.SetSelectionOwnerChecked(tray.X.Conn(), tray.wid.Id, sysTrayAtom, tray.X.TimeGet()).Check() if err != nil { return nil, err } reply, err := xproto.GetSelectionOwner(X.Conn(), sysTrayAtom).Reply() if err != nil { return nil, err } if reply.Owner != tray.wid.Id { return nil, fmt.Errorf("Could not get ownership of the thingy-thing.") } evt, err := xevent.NewClientMessage(32, X.RootWin(), managerEventAtom, int(X.TimeGet()), int(sysTrayAtom), int(tray.wid.Id)) if err != nil { return nil, err } if err = xevent.SendRootEvent(X, evt, xproto.EventMaskStructureNotify); err != nil { return nil, err } xevent.ClientMessageFun(func(_ *xgbutil.XUtil, ev xevent.ClientMessageEvent) { tray.event(ev) }).Connect(tray.X, tray.wid.Id) return tray, nil }
func (m *TrayManager) getSelectionOwner() (*xproto.GetSelectionOwnerReply, error) { _trayInstance := xproto.GetSelectionOwner(TrayXU.Conn(), _NET_SYSTEM_TRAY_S0) return _trayInstance.Reply() }