// 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.Level = buf[b] b += 1 v.Sequence = xgb.Get16(buf[b:]) b += 2 v.Drawable = xproto.Drawable(xgb.Get32(buf[b:])) b += 4 v.Damage = Damage(xgb.Get32(buf[b:])) b += 4 v.Timestamp = xproto.Timestamp(xgb.Get32(buf[b:])) b += 4 v.Area = xproto.Rectangle{} b += xproto.RectangleRead(buf[b:], &v.Area) v.Geometry = xproto.Rectangle{} b += xproto.RectangleRead(buf[b:], &v.Geometry) return v }
// 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.State = buf[b] b += 1 v.Sequence = xgb.Get16(buf[b:]) b += 2 v.Time = xproto.Timestamp(xgb.Get32(buf[b:])) b += 4 v.Root = xproto.Window(xgb.Get32(buf[b:])) b += 4 v.Window = xproto.Window(xgb.Get32(buf[b:])) b += 4 v.Kind = buf[b] b += 1 if buf[b] == 1 { v.Forced = true } else { v.Forced = false } b += 1 b += 14 // padding return v }
func (c *Client) handleProperty(name string) { switch name { case "_NET_WM_VISIBLE_NAME": fallthrough case "_NET_WM_NAME": fallthrough case "WM_NAME": c.refreshName() case "_NET_WM_ICON": c.refreshIcon() case "WM_HINTS": if hints, err := icccm.WmHintsGet(wm.X, c.Id()); err == nil { c.hints = hints c.refreshIcon() } case "WM_NORMAL_HINTS": if nhints, err := icccm.WmNormalHintsGet(wm.X, c.Id()); err == nil { c.nhints = nhints } case "WM_TRANSIENT_FOR": if trans, err := icccm.WmTransientForGet(wm.X, c.Id()); err == nil { if transCli := wm.FindManagedClient(trans); transCli != nil { c.transientFor = transCli.(*Client) } } case "_NET_WM_USER_TIME": if newTime, err := ewmh.WmUserTimeGet(wm.X, c.Id()); err == nil { c.time = xproto.Timestamp(newTime) } case "_NET_WM_STRUT_PARTIAL": c.maybeApplyStruts() case "_MOTIF_WM_HINTS": // This is a bit messed up. If a client is floating, we don't // really care what the decorations are, so we oblige blindly. // However, if we're tiling, then we don't want to mess with // the frames---but we also want to make sure that any states // the client might revert to have the proper frames. decor := c.shouldDecor() if _, ok := c.Layout().(layout.Floater); ok { if decor { c.FrameFull() } else { c.FrameNada() } } else { for k := range c.states { s := c.states[k] if decor { s.frame = c.frames.full } else { s.frame = c.frames.nada } c.states[k] = s } } } }
func (m *TrayManager) tryOwner() bool { // Make a check, the tray application MUST be 1. reply, err := m.getSelectionOwner() if err != nil { logger.Error(err) return false } if reply.Owner != 0 { logger.Warning("Another System tray application is running") return false } timeStamp, _ := ewmh.WmUserTimeGet(TrayXU, m.owner) err = xproto.SetSelectionOwnerChecked( TrayXU.Conn(), m.owner, _NET_SYSTEM_TRAY_S0, xproto.Timestamp(timeStamp), ).Check() if err != nil { logger.Warning("Set Selection Owner failed: ", err) return false } //owner the _NET_SYSTEM_TRAY_Sn logger.Info("Required _NET_SYSTEM_TRAY_S0 successful") m.RequireManageTrayIcons() xprop.ChangeProp32( TrayXU, m.owner, "_NET_SYSTEM_TRAY_VISUAL", "VISUALID", uint(TRAYMANAGER.visual), ) xprop.ChangeProp32( TrayXU, m.owner, "_NET_SYSTEM_TRAY_ORIENTAION", "CARDINAL", 0, ) reply, err = m.getSelectionOwner() if err != nil { logger.Warning(err) return false } return reply.Owner != 0 }
func (c *client) cbPropertyNotify() xevent.PropertyNotifyFun { // helper function to log property vals showVals := func(o, n interface{}) { logger.Lots.Printf("\tOld value: '%s', new value: '%s'", o, n) } f := func(X *xgbutil.XUtil, ev xevent.PropertyNotifyEvent) { name, err := xprop.AtomName(c.X, ev.Atom) if err != nil { logger.Warning.Printf("Could not get property atom name for '%s' "+ "because: %s.", ev, err) } logger.Lots.Printf("Updating property %s with state %v on window %s", name, ev.State, c) switch name { case "_NET_WM_VISIBLE_NAME": fallthrough case "_NET_WM_NAME": fallthrough case "WM_NAME": c.refreshName() case "_NET_WM_ICON": case "WM_HINTS": if hints, err := icccm.WmHintsGet(X, c.Id()); err == nil { c.hints = hints } case "WM_NORMAL_HINTS": if nhints, err := icccm.WmNormalHintsGet(X, c.Id()); err == nil { c.nhints = nhints } case "WM_TRANSIENT_FOR": if trans, err := icccm.WmTransientForGet(X, c.Id()); err == nil { if transCli := wingo.findManagedClient(trans); transCli != nil { c.transientFor = transCli } } case "_NET_WM_USER_TIME": if newTime, err := ewmh.WmUserTimeGet(X, c.Id()); err == nil { showVals(c.time, newTime) c.time = xproto.Timestamp(newTime) } case "_NET_WM_STRUT_PARTIAL": } } return xevent.PropertyNotifyFun(f) }
// 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 }
// WMTakeFocus will do all the necessary setup to support the WM_TAKE_FOCUS // protocol using the "LocallyActive" input model described in Section 4.1.7 // of the ICCCM. Namely, listening to ClientMessage events and running the // callback function provided when a WM_TAKE_FOCUS ClientMessage has been // received. // // Typically, the callback function should include a call to SetInputFocus // with the "Parent" InputFocus type, the sub-window id of the window that // should have focus, and the 'tstamp' timestamp. func (w *Window) WMTakeFocus(cb func(w *Window, tstamp xproto.Timestamp)) { // Make sure the Input flag is set to true in WM_HINTS. We first // must retrieve the current WM_HINTS, so we don't overwrite the flags. curFlags := 0 if hints, err := icccm.WmHintsGet(w.X, w.Id); err == nil { curFlags = hints.Flags } icccm.WmHintsSet(w.X, w.Id, &icccm.Hints{ Flags: curFlags | icccm.HintInput, Input: 1, }) // Get the current protocols so we don't overwrite anything. prots, _ := icccm.WmProtocolsGet(w.X, w.Id) // If WM_TAKE_FOCUS isn't here, add it. Otherwise, move on. wmfocus := false for _, prot := range prots { if prot == "WM_TAKE_FOCUS" { wmfocus = true break } } if !wmfocus { icccm.WmProtocolsSet(w.X, w.Id, append(prots, "WM_TAKE_FOCUS")) } // Attach a ClientMessage event handler. It will determine whether the // ClientMessage is a 'focus' request, and if so, run the callback 'cb' // provided. xevent.ClientMessageFun( func(X *xgbutil.XUtil, ev xevent.ClientMessageEvent) { if icccm.IsFocusProtocol(X, ev) { cb(w, xproto.Timestamp(ev.Data.Data32[1])) } }).Connect(w.X, w.Id) }
func (m *TrayManager) Unmanage() bool { reply, err := m.getSelectionOwner() if err != nil { logger.Warning("get selection owner failed:", err) return false } if reply.Owner != m.owner { logger.Warning("not selection owner") return false } m.destroyOwnerWindow() trayicons := m.TrayIcons for _, icon := range trayicons { m.removeTrayIcon(xproto.Window(icon)) } timeStamp, _ := ewmh.WmUserTimeGet(TrayXU, m.owner) return xproto.SetSelectionOwnerChecked( TrayXU.Conn(), 0, _NET_SYSTEM_TRAY_S0, xproto.Timestamp(timeStamp), ).Check() == nil }
func (s *screenImpl) run() { for { ev, err := s.xc.WaitForEvent() if err != nil { log.Printf("x11driver: xproto.WaitForEvent: %v", err) continue } noWindowFound := false switch ev := ev.(type) { case xproto.DestroyNotifyEvent: s.mu.Lock() delete(s.windows, ev.Window) s.mu.Unlock() case shm.CompletionEvent: s.mu.Lock() s.completionKeys = append(s.completionKeys, ev.Sequence) s.handleCompletions() s.mu.Unlock() case xproto.ClientMessageEvent: if ev.Type != s.atomWMProtocols || ev.Format != 32 { break } switch xproto.Atom(ev.Data.Data32[0]) { case s.atomWMDeleteWindow: // TODO. case s.atomWMTakeFocus: xproto.SetInputFocus(s.xc, xproto.InputFocusParent, ev.Window, xproto.Timestamp(ev.Data.Data32[1])) } case xproto.ConfigureNotifyEvent: if w := s.findWindow(ev.Window); w != nil { w.handleConfigureNotify(ev) } else { noWindowFound = true } case xproto.ExposeEvent: if w := s.findWindow(ev.Window); w != nil { // A non-zero Count means that there are more expose events // coming. For example, a non-rectangular exposure (e.g. from a // partially overlapped window) will result in multiple expose // events whose dirty rectangles combine to define the dirty // region. Go's paint events do not provide dirty regions, so // we only pass on the final X11 expose event. if ev.Count == 0 { w.handleExpose() } } else { noWindowFound = true } case xproto.FocusInEvent: // TODO: xw = ev.Event case xproto.FocusOutEvent: // TODO: xw = ev.Event case xproto.KeyPressEvent: if w := s.findWindow(ev.Event); w != nil { w.handleKey(ev.Detail, ev.State, key.DirPress) } else { noWindowFound = true } case xproto.KeyReleaseEvent: if w := s.findWindow(ev.Event); w != nil { w.handleKey(ev.Detail, ev.State, key.DirRelease) } else { noWindowFound = true } case xproto.ButtonPressEvent: if w := s.findWindow(ev.Event); w != nil { w.handleMouse(ev.EventX, ev.EventY, ev.Detail, ev.State, mouse.DirPress) } else { noWindowFound = true } case xproto.ButtonReleaseEvent: if w := s.findWindow(ev.Event); w != nil { w.handleMouse(ev.EventX, ev.EventY, ev.Detail, ev.State, mouse.DirRelease) } else { noWindowFound = true } case xproto.MotionNotifyEvent: if w := s.findWindow(ev.Event); w != nil { w.handleMouse(ev.EventX, ev.EventY, 0, ev.State, mouse.DirNone) } else { noWindowFound = true } } if noWindowFound { log.Printf("x11driver: no window found for event %T", ev) } } }
func (s *screenImpl) run() { for { ev, err := s.xc.WaitForEvent() if err != nil { log.Printf("x11driver: xproto.WaitForEvent: %v", err) continue } noWindowFound := false switch ev := ev.(type) { case xproto.DestroyNotifyEvent: s.mu.Lock() delete(s.windows, ev.Window) s.mu.Unlock() case shm.CompletionEvent: s.handleCompletion(ev) case xproto.ClientMessageEvent: if ev.Type != s.atomWMProtocols || ev.Format != 32 { break } switch xproto.Atom(ev.Data.Data32[0]) { case s.atomWMDeleteWindow: // TODO. case s.atomWMTakeFocus: xproto.SetInputFocus(s.xc, xproto.InputFocusParent, ev.Window, xproto.Timestamp(ev.Data.Data32[1])) } case xproto.ConfigureNotifyEvent: if w := s.findWindow(ev.Window); w != nil { w.handleConfigureNotify(ev) } else { noWindowFound = true } case xproto.ExposeEvent: // TODO: xw = ev.Window case xproto.FocusInEvent: // TODO: xw = ev.Event case xproto.FocusOutEvent: // TODO: xw = ev.Event case xproto.KeyPressEvent: // TODO: xw = ev.Event case xproto.KeyReleaseEvent: // TODO: xw = ev.Event case xproto.ButtonPressEvent: if w := s.findWindow(ev.Event); w != nil { w.handleMouse(ev.EventX, ev.EventY, ev.Detail, ev.State, mouse.DirPress) } else { noWindowFound = true } case xproto.ButtonReleaseEvent: if w := s.findWindow(ev.Event); w != nil { w.handleMouse(ev.EventX, ev.EventY, ev.Detail, ev.State, mouse.DirRelease) } else { noWindowFound = true } case xproto.MotionNotifyEvent: if w := s.findWindow(ev.Event); w != nil { w.handleMouse(ev.EventX, ev.EventY, 0, ev.State, mouse.DirNone) } else { noWindowFound = true } } if noWindowFound { log.Printf("x11driver: no window found for event %T", ev) } } }
// NewConnXgb use the specific xgb.Conn to create a new XUtil. // // NewConn, NewConnDisplay are wrapper of this function. func NewConnXgb(c *xgb.Conn) (*XUtil, error) { setup := xproto.Setup(c) screen := setup.DefaultScreen(c) // Initialize our central struct that stores everything. xu := &XUtil{ conn: c, Quit: false, Evqueue: make([]EventOrError, 0, 1000), EvqueueLck: &sync.RWMutex{}, setup: setup, screen: screen, root: screen.Root, eventTime: xproto.Timestamp(0), // last event time Atoms: make(map[string]xproto.Atom, 50), AtomsLck: &sync.RWMutex{}, AtomNames: make(map[xproto.Atom]string, 50), AtomNamesLck: &sync.RWMutex{}, Callbacks: make(map[int]map[xproto.Window][]Callback, 33), CallbacksLck: &sync.RWMutex{}, Hooks: make([]CallbackHook, 0), HooksLck: &sync.RWMutex{}, Keymap: nil, // we don't have anything yet Modmap: nil, KeyRedirect: 0, Keybinds: make(map[KeyKey][]CallbackKey, 10), KeybindsLck: &sync.RWMutex{}, Keygrabs: make(map[KeyKey]int, 10), Keystrings: make([]KeyString, 0, 10), Mousebinds: make(map[MouseKey][]CallbackMouse, 10), MousebindsLck: &sync.RWMutex{}, Mousegrabs: make(map[MouseKey]int, 10), InMouseDrag: false, MouseDragStepFun: nil, MouseDragEndFun: nil, ErrorHandler: func(err xgb.Error) { Logger.Println(err) }, } var err error = nil // Create a general purpose graphics context xu.gc, err = xproto.NewGcontextId(xu.conn) if err != nil { return nil, err } xproto.CreateGC(xu.conn, xu.gc, xproto.Drawable(xu.root), xproto.GcForeground, []uint32{xu.screen.WhitePixel}) // Create a dummy window xu.dummy, err = xproto.NewWindowId(xu.conn) if err != nil { return nil, err } xproto.CreateWindow(xu.conn, xu.Screen().RootDepth, xu.dummy, xu.RootWin(), -1000, -1000, 1, 1, 0, xproto.WindowClassInputOutput, xu.Screen().RootVisual, xproto.CwEventMask|xproto.CwOverrideRedirect, []uint32{1, xproto.EventMaskPropertyChange}) xproto.MapWindow(xu.conn, xu.dummy) // Register the Xinerama extension... because it doesn't cost much. err = xinerama.Init(xu.conn) // If we can't register Xinerama, that's okay. Output something // and move on. if err != nil { Logger.Printf("WARNING: %s\n", err) Logger.Printf("MESSAGE: The 'xinerama' package cannot be used " + "because the XINERAMA extension could not be loaded.") } return xu, nil }