func (c *Client) handleClientMessage(name string, data []uint32) { switch name { case "WM_CHANGE_STATE": if data[0] == icccm.StateIconic && !c.iconified { c.IconifyToggle() } case "_NET_ACTIVE_WINDOW": c.Focus() c.Raise() case "_NET_CLOSE_WINDOW": c.Close() case "_NET_MOVERESIZE_WINDOW": // The data[0] element contains bit-packed information. See // EWMH _NET_MOVERESIZE_WINDOW for the deets. gravity := int(data[0] & 0xff) xflags := int((data[0] >> 8) & 0xf) x, y, w, h := frame.ClientToFrame(c.frame, gravity, int(data[1]), int(data[2]), int(data[3]), int(data[4])) c.LayoutMROpt(xflags, x, y, w, h) case "_NET_RESTACK_WINDOW": // We basically treat this as a request to stack the window. // We ignore the sibling. Maybe someday we can support that, but eh... c.Raise() case "_NET_WM_DESKTOP": if data[0] == 0xFFFFFFFF { c.stick() return } if wrk := wm.Heads.Workspaces.Get(int(data[0])); wrk != nil { wrk.Add(c) } else { logger.Warning.Printf( "_NET_WM_DESKTOP ClientMessage: No workspace indexed at '%d' "+ "exists.", data[0]) } case "_NET_WM_STATE": prop1, _ := xprop.AtomName(wm.X, xproto.Atom(data[1])) prop2, _ := xprop.AtomName(wm.X, xproto.Atom(data[2])) switch data[0] { case 0: c.updateStates("remove", prop1, prop2) case 1: c.updateStates("add", prop1, prop2) case 2: c.updateStates("toggle", prop1, prop2) default: logger.Warning.Printf( "_NET_WM_STATE: Unknown action '%d'.", data[0]) } default: logger.Warning.Printf("Unknown ClientMessage for '%s': %s.", c, name) } }
func (a *atomic) PropValAtom(reply *xproto.GetPropertyReply, err error) (string, error) { if err != nil { return "", err } if reply.Format != 32 { return "", fmt.Errorf("PropValAtom: Expected format 32 but got %d", reply.Format) } return a.AtomName(xproto.Atom(xgb.Get32(reply.Value))) }
// TypeRead reads a byte slice into a Type value. func TypeRead(buf []byte, v *Type) int { b := 0 v.ResourceType = xproto.Atom(xgb.Get32(buf[b:])) b += 4 v.Count = xgb.Get32(buf[b:]) b += 4 return b }
func (a *atomic) PropValAtoms(reply *xproto.GetPropertyReply, err error) ([]string, error) { if err != nil { return nil, err } if reply.Format != 32 { return nil, fmt.Errorf("PropValAtoms: Expected format 32 but got %d", reply.Format) } ids := make([]string, reply.ValueLen) vals := reply.Value for i := 0; len(vals) >= 4; i++ { ids[i], err = a.AtomName(xproto.Atom(xgb.Get32(vals))) if err != nil { return nil, err } vals = vals[4:] } return ids, nil }
// IsFocusProtocol checks whether a ClientMessage event satisfies the // WM_TAKE_FOCUS protocol. func IsFocusProtocol(X *xgbutil.XUtil, ev xevent.ClientMessageEvent) bool { // Make sure the Format is 32. (Meaning that each data item is // 32 bits.) if ev.Format != 32 { return false } // Check to make sure the Type atom is WM_PROTOCOLS. typeName, err := xprop.AtomName(X, ev.Type) if err != nil || typeName != "WM_PROTOCOLS" { // not what we want return false } // Check to make sure the first data item is WM_TAKE_FOCUS. protocolType, err := xprop.AtomName(X, xproto.Atom(ev.Data.Data32[0])) if err != nil || protocolType != "WM_TAKE_FOCUS" { return false } return true }
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) } } }
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() }
func main() { // Open the connection to the X server X, err := xgb.NewConn() if err != nil { log.Fatal(err) } defer X.Close() setup := xproto.Setup(X) // Get the first screen screen := setup.DefaultScreen(X) // Replace existing window manager wmName := fmt.Sprintf("WM_S%d", X.DefaultScreen) managerAtom, err := xproto.InternAtom(X, true, uint16(len(wmName)), wmName).Reply() if err != nil { log.Fatal(err) } fakeWindow, _ := xproto.NewWindowId(X) xproto.CreateWindow(X, // Connection screen.RootDepth, // Depth fakeWindow, // Window Id screen.Root, // Parent Window -1000, -1000, // x, y 1, 1, // width, height 0, // border_width xproto.WindowClassInputOutput, // class screen.RootVisual, // visual xproto.CwEventMask|xproto.CwOverrideRedirect, []uint32{1, xproto.EventMaskPropertyChange}) // masks xproto.MapWindow(X, fakeWindow) err = xproto.SetSelectionOwnerChecked(X, fakeWindow, managerAtom.Atom, xproto.TimeCurrentTime).Check() if err != nil { fmt.Println("foo") log.Fatal(err) } arcs := []xproto.Arc{ {10, 100, 60, 40, 0, 90 << 6}, {90, 100, 55, 40, 0, 270 << 6}} // Create black (foreground) graphic context foreground, _ := xproto.NewGcontextId(X) mask := uint32(xproto.GcForeground | xproto.GcGraphicsExposures) values := []uint32{screen.BlackPixel, 0} xproto.CreateGC(X, foreground, xproto.Drawable(screen.Root), mask, values) // Ask for our window's Id win, _ := xproto.NewWindowId(X) winDrawable := xproto.Drawable(win) // Create the window mask = uint32(xproto.CwBackPixel | xproto.CwEventMask) values = []uint32{screen.WhitePixel, xproto.EventMaskExposure} xproto.CreateWindow(X, // Connection screen.RootDepth, // Depth win, // Window Id screen.Root, // Parent Window 0, 0, // x, y 150, 150, // width, height 10, // border_width xproto.WindowClassInputOutput, // class screen.RootVisual, // visual mask, values) // masks // Map the window on the screen xproto.MapWindow(X, win) // Obey the window-delete protocol tp := "WM_PROTOCOLS" prp := "WM_DELETE_WINDOW" typeAtom, _ := xproto.InternAtom(X, true, uint16(len(tp)), tp).Reply() propertyAtom, _ := xproto.InternAtom(X, true, uint16(len(prp)), prp).Reply() data := make([]byte, 4) xgb.Put32(data, uint32(propertyAtom.Atom)) xproto.ChangeProperty(X, xproto.PropModeReplace, win, typeAtom.Atom, xproto.AtomAtom, 32, 1, data) // Main loop for { evt, err := X.WaitForEvent() fmt.Printf("An event of type %T occured.\n", evt) if evt == nil && err == nil { fmt.Println("Exiting....") return } else if err != nil { log.Fatal(err) } switch event := evt.(type) { case xproto.ExposeEvent: /* We draw the arcs */ xproto.PolyArc(X, winDrawable, foreground, arcs) case xproto.ClientMessageEvent: if len(event.Data.Data32) > 0 { data := xproto.Atom(event.Data.Data32[0]) if data == propertyAtom.Atom { return } else { atomName, _ := xproto.GetAtomName(X, data).Reply() fmt.Println(atomName.Name) } } else { atomName, _ := xproto.GetAtomName(X, event.Type).Reply() fmt.Println(atomName.Name) } default: /* Unknown event type, ignore it */ } } return }
func main() { // Open the connection to the X server X, err := xgb.NewConn() if err != nil { log.Fatal(err) } defer X.Close() // geometric objects points := []xproto.Point{ {10, 10}, {10, 20}, {20, 10}, {20, 20}} polyline := []xproto.Point{ {50, 10}, {5, 20}, // rest of points are relative {25, -20}, {10, 10}} segments := []xproto.Segment{ {100, 10, 140, 30}, {110, 25, 130, 60}} rectangles := []xproto.Rectangle{ {10, 50, 40, 20}, {80, 50, 10, 40}} arcs := []xproto.Arc{ {10, 100, 60, 40, 0, 90 << 6}, {90, 100, 55, 40, 0, 270 << 6}} setup := xproto.Setup(X) // Get the first screen screen := setup.DefaultScreen(X) // Create black (foreground) graphic context foreground, _ := xproto.NewGcontextId(X) mask := uint32(xproto.GcForeground | xproto.GcGraphicsExposures) values := []uint32{screen.BlackPixel, 0} xproto.CreateGC(X, foreground, xproto.Drawable(screen.Root), mask, values) // Ask for our window's Id win, _ := xproto.NewWindowId(X) winDrawable := xproto.Drawable(win) // Create the window mask = uint32(xproto.CwBackPixel | xproto.CwEventMask) values = []uint32{screen.WhitePixel, xproto.EventMaskExposure} xproto.CreateWindow(X, // Connection screen.RootDepth, // Depth win, // Window Id screen.Root, // Parent Window 0, 0, // x, y 150, 150, // width, height 10, // border_width xproto.WindowClassInputOutput, // class screen.RootVisual, // visual mask, values) // masks // Map the window on the screen xproto.MapWindow(X, win) // Obey the window-delete protocol tp := "WM_PROTOCOLS" prp := "WM_DELETE_WINDOW" typeAtom, _ := xproto.InternAtom(X, true, uint16(len(tp)), tp).Reply() propertyAtom, _ := xproto.InternAtom(X, true, uint16(len(prp)), prp).Reply() // It turns out that we need the window ID as a byte-stream... WTF!! // xprop.ChangeProp(xu, win, 8, "WM_NAME", "STRING", ([]byte)(name)) // ChangeProp(xu *xgbutil.XUtil, win xproto.Window, format byte, prop string, typ string, data []byte) data := make([]byte, 4) xgb.Put32(data, uint32(propertyAtom.Atom)) xproto.ChangeProperty(X, xproto.PropModeReplace, win, typeAtom.Atom, xproto.AtomAtom, 32, 1, data) for { evt, err := X.WaitForEvent() fmt.Printf("An event of type %T occured.\n", evt) if evt == nil && err == nil { fmt.Println("Exiting....") return } else if err != nil { log.Fatal(err) } switch event := evt.(type) { case xproto.ExposeEvent: /* We draw the points */ xproto.PolyPoint(X, xproto.CoordModeOrigin, winDrawable, foreground, points) /* We draw the polygonal line */ xproto.PolyLine(X, xproto.CoordModePrevious, winDrawable, foreground, polyline) /* We draw the segments */ xproto.PolySegment(X, winDrawable, foreground, segments) /* We draw the rectangles */ xproto.PolyRectangle(X, winDrawable, foreground, rectangles) /* We draw the arcs */ xproto.PolyArc(X, winDrawable, foreground, arcs) case xproto.ClientMessageEvent: if len(event.Data.Data32) > 0 { data := xproto.Atom(event.Data.Data32[0]) if data == propertyAtom.Atom { return } else { atomName, _ := xproto.GetAtomName(X, data).Reply() fmt.Println(atomName.Name) } } else { atomName, _ := xproto.GetAtomName(X, event.Type).Reply() fmt.Println(atomName.Name) } default: /* Unknown event type, ignore it */ } } return }