func main() { X, err := xgb.NewConn() if err != nil { fmt.Println(err) return } // xproto.Setup retrieves the Setup information from the setup bytes // gathered during connection. setup := xproto.Setup(X) // This is the default screen with all its associated info. screen := setup.DefaultScreen(X) // Any time a new resource (i.e., a window, pixmap, graphics context, etc.) // is created, we need to generate a resource identifier. // If the resource is a window, then use xproto.NewWindowId. If it's for // a pixmap, then use xproto.NewPixmapId. And so on... wid, _ := xproto.NewWindowId(X) // CreateWindow takes a boatload of parameters. xproto.CreateWindow(X, screen.RootDepth, wid, screen.Root, 0, 0, 500, 500, 0, xproto.WindowClassInputOutput, screen.RootVisual, 0, []uint32{}) // This call to ChangeWindowAttributes could be factored out and // included with the above CreateWindow call, but it is left here for // instructive purposes. It tells X to send us events when the 'structure' // of the window is changed (i.e., when it is resized, mapped, unmapped, // etc.) and when a key press or a key release has been made when the // window has focus. // We also set the 'BackPixel' to white so that the window isn't butt ugly. xproto.ChangeWindowAttributes(X, wid, xproto.CwBackPixel|xproto.CwEventMask, []uint32{ // values must be in the order defined by the protocol 0xffffffff, xproto.EventMaskStructureNotify | xproto.EventMaskKeyPress | xproto.EventMaskKeyRelease}) // MapWindow makes the window we've created appear on the screen. // We demonstrated the use of a 'checked' request here. // A checked request is a fancy way of saying, "do error handling // synchronously." Namely, if there is a problem with the MapWindow request, // we'll get the error *here*. If we were to do a normal unchecked // request (like the above CreateWindow and ChangeWindowAttributes // requests), then we would only see the error arrive in the main event // loop. // // Typically, checked requests are useful when you need to make sure they // succeed. Since they are synchronous, they incur a round trip cost before // the program can continue, but this is only going to be noticeable if // you're issuing tons of requests in succession. // // Note that requests without replies are by default unchecked while // requests *with* replies are checked by default. err = xproto.MapWindowChecked(X, wid).Check() if err != nil { fmt.Printf("Checked Error for mapping window %d: %s\n", wid, err) } else { fmt.Printf("Map window %d successful!\n", wid) } // This is an example of an invalid MapWindow request and what an error // looks like. err = xproto.MapWindowChecked(X, 0).Check() if err != nil { fmt.Printf("Checked Error for mapping window 0x1: %s\n", err) } else { // neva fmt.Printf("Map window 0x1 successful!\n") } // Start the main event loop. for { // WaitForEvent either returns an event or an error and never both. // If both are nil, then something went wrong and the loop should be // halted. // // An error can only be seen here as a response to an unchecked // request. ev, xerr := X.WaitForEvent() if ev == nil && xerr == nil { fmt.Println("Both event and error are nil. Exiting...") return } if ev != nil { fmt.Printf("Event: %s\n", ev) } if xerr != nil { fmt.Printf("Error: %s\n", xerr) } } }
func initDesktop(xScreen *xp.ScreenInfo) { xFont, err := xp.NewFontId(xConn) if err != nil { log.Fatal(err) } xCursor, err := xp.NewCursorId(xConn) if err != nil { log.Fatal(err) } err = xp.OpenFontChecked(xConn, xFont, uint16(len("cursor")), "cursor").Check() if err != nil { log.Fatal(err) } const xcLeftPtr = 68 // XC_left_ptr from cursorfont.h. err = xp.CreateGlyphCursorChecked( xConn, xCursor, xFont, xFont, xcLeftPtr, xcLeftPtr+1, 0xffff, 0xffff, 0xffff, 0, 0, 0).Check() if err != nil { log.Fatal(err) } err = xp.CloseFontChecked(xConn, xFont).Check() if err != nil { log.Fatal(err) } desktopXWin, err = xp.NewWindowId(xConn) if err != nil { log.Fatal(err) } desktopXGC, err = xp.NewGcontextId(xConn) if err != nil { log.Fatal(err) } desktopWidth = xScreen.WidthInPixels desktopHeight = xScreen.HeightInPixels if err := xp.CreateWindowChecked( xConn, xScreen.RootDepth, desktopXWin, xScreen.Root, 0, 0, desktopWidth, desktopHeight, 0, xp.WindowClassInputOutput, xScreen.RootVisual, xp.CwOverrideRedirect|xp.CwEventMask, []uint32{ 1, xp.EventMaskExposure, }, ).Check(); err != nil { log.Fatal(err) } if len(xSettings) != 0 { initXSettings() } if err := xp.ConfigureWindowChecked( xConn, desktopXWin, xp.ConfigWindowStackMode, []uint32{ xp.StackModeBelow, }, ).Check(); err != nil { log.Fatal(err) } if err := xp.ChangeWindowAttributesChecked( xConn, desktopXWin, xp.CwBackPixel|xp.CwCursor, []uint32{ xScreen.BlackPixel, uint32(xCursor), }, ).Check(); err != nil { log.Fatal(err) } if err := xp.CreateGCChecked( xConn, desktopXGC, xp.Drawable(xScreen.Root), 0, nil, ).Check(); err != nil { log.Fatal(err) } if err := xp.MapWindowChecked(xConn, desktopXWin).Check(); err != nil { log.Fatal(err) } }
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() }