func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Read an example gopher image into a regular png image. img, _, err := image.Decode(bytes.NewBuffer(gopher.GopherPng())) if err != nil { log.Fatal(err) } // Now convert it into an X image. ximg := xgraphics.NewConvert(X, img) // Now show it in a new window. // We set the window title and tell the program to quit gracefully when // the window is closed. // There is also a convenience method, XShow, that requires no parameters. ximg.XShowExtra("The Go Gopher!", true) // If we don't block, the program will end and the window will disappear. // We could use a 'select{}' here, but xevent.Main will emit errors if // something went wrong, so use that instead. xevent.Main(X) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Use the "NewDrawable" constructor to create an xgraphics.Image value // from a drawable. (Usually this is done with pixmaps, but drawables // can also be windows.) ximg, err := xgraphics.NewDrawable(X, xproto.Drawable(X.RootWin())) if err != nil { log.Fatal(err) } // Shows the screenshot in a window. ximg.XShowExtra("Screenshot", true) // If you'd like to save it as a png, use: // err = ximg.SavePng("screenshot.png") // if err != nil { // log.Fatal(err) // } xevent.Main(X) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Create window for receiving compressed MotionNotify events. cwin := newWindow(X, 0x00ff00) // Attach event handler for MotionNotify that compresses events. xevent.MotionNotifyFun( func(X *xgbutil.XUtil, ev xevent.MotionNotifyEvent) { ev = compressMotionNotify(X, ev) fmt.Printf("COMPRESSED: (EventX %d, EventY %d)\n", ev.EventX, ev.EventY) time.Sleep(workTime) }).Connect(X, cwin.Id) // Create window for receiving uncompressed MotionNotify events. uwin := newWindow(X, 0xff0000) // Attach event handler for MotionNotify that does not compress events. xevent.MotionNotifyFun( func(X *xgbutil.XUtil, ev xevent.MotionNotifyEvent) { fmt.Printf("UNCOMPRESSED: (EventX %d, EventY %d)\n", ev.EventX, ev.EventY) time.Sleep(workTime) }).Connect(X, uwin.Id) xevent.Main(X) }
func NewWindow(width, height int) (wde.Window, error) { var err error w := new(Window) w.width, w.height = width, height w.xu, err = xgbutil.NewConn() if err != nil { return nil, err } w.conn = w.xu.Conn() screen := w.xu.Screen() w.win, err = xwindow.Generate(w.xu) if err != nil { return nil, err } err = w.win.CreateChecked(screen.Root, 600, 500, width, height, 0) if err != nil { return nil, err } w.win.Listen(AllEventsMask) err = icccm.WmProtocolsSet(w.xu, w.win.Id, []string{"WM_DELETE_WINDOW"}) if err != nil { fmt.Println(err) err = nil } w.bufferLck = &sync.Mutex{} w.buffer = xgraphics.New(w.xu, image.Rect(0, 0, width, height)) w.buffer.XSurfaceSet(w.win.Id) keyMap, modMap := keybind.MapsGet(w.xu) keybind.KeyMapSet(w.xu, keyMap) keybind.ModMapSet(w.xu, modMap) w.events = make(chan interface{}) w.SetIcon(Gordon) w.SetIconName("Go") go w.handleEvents() return w, nil }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Start generating other source events. otherChan := otherSource() // Start generating X events (by sending client messages to root window). go xSource(X) // Listen to those X events. xwindow.New(X, X.RootWin()).Listen(xproto.EventMaskSubstructureNotify) // Respond to those X events. xevent.ClientMessageFun( func(X *xgbutil.XUtil, ev xevent.ClientMessageEvent) { atmName, err := xprop.AtomName(X, ev.Type) if err != nil { log.Fatal(err) } fmt.Printf("ClientMessage: %d. %s\n", ev.Data.Data32[0], atmName) }).Connect(X, X.RootWin()) // Instead of using the usual xevent.Main, we use xevent.MainPing. // It runs the main event loop inside a goroutine and returns ping // channels, which are sent benign values right before an event is // dequeued and right after that event has finished running all callbacks // associated with it, respectively. pingBefore, pingAfter, pingQuit := xevent.MainPing(X) for { select { case <-pingBefore: // Wait for the event to finish processing. <-pingAfter case otherVal := <-otherChan: fmt.Printf("Processing other event: %d\n", otherVal) case <-pingQuit: fmt.Printf("xevent loop has quit") return } } }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Get a list of all client ids. clientids, err := ewmh.ClientListGet(X) if err != nil { log.Fatal(err) } // Iterate through each client, find its name and find its size. for _, clientid := range clientids { name, err := ewmh.WmNameGet(X, clientid) // If there was a problem getting _NET_WM_NAME or if its empty, // try the old-school version. if err != nil || len(name) == 0 { name, err = icccm.WmNameGet(X, clientid) // If we still can't find anything, give up. if err != nil || len(name) == 0 { name = "N/A" } } // Now find the geometry, including decorations, of the client window. // Note that DecorGeometry actually traverses the window tree by // issuing QueryTree requests until a top-level window (i.e., its // parent is the root window) is found. The geometry of *that* window // is then returned. dgeom, err := xwindow.New(X, clientid).DecorGeometry() if err != nil { log.Printf("Could not get geometry for %s (0x%X) because: %s", name, clientid, err) continue } fmt.Printf("%s (0x%x)\n", name, clientid) fmt.Printf("\tGeometry: %s\n", dgeom) } }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Anytime the mousebind (keybind) package is used, mousebind.Initialize // *should* be called once. In the case of the mousebind package, this // isn't strictly necessary (currently!), but the 'Drag' features of // the mousebind package won't work without it. mousebind.Initialize(X) // Create two windows to prove we can close one while keeping the // other alive. newWindow(X) newWindow(X) xevent.Main(X) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Create the cursor. You can find a list of available cursors in // xcursor/cursordef.go. // We'll make an umbrella here, with an orange foreground and a blue // background. (The background it typically the outline of the cursor.) // Note that each component of the RGB color is a 16 bit color. I think // using the most significant byte to specify each component is good // enough. cursor, err := xcursor.CreateCursorExtra(X, xcursor.Umbrella, 0xff00, 0x5500, 0x0000, 0x3300, 0x6600, 0xff00) if err != nil { log.Fatal(err) } // Create a new window. In the create window request, we'll set the // background color and set the cursor we created above. // This results in changing the cursor only when it moves into this window. win, err := xwindow.Generate(X) if err != nil { log.Fatal(err) } win.Create(X.RootWin(), 0, 0, 500, 500, xproto.CwBackPixel|xproto.CwCursor, 0xffffffff, uint32(cursor)) win.Map() // We can free the cursor now that we've set it. // If you plan on using this cursor again, then it shouldn't be freed. // (i.e., if you try to free this before setting it as the cursor in a // window, you'll get a BadCursor error when trying to use it.) xproto.FreeCursor(X.Conn(), cursor) // Block. No need to process any events. select {} }
func main() { X, err := xgbutil.NewConn() fatal(err) // Whenever the mousebind package is used, you must call Initialize. // Similarly for the keybind package. keybind.Initialize(X) mousebind.Initialize(X) // Easter egg! Use a right click to draw a gopher. gopherPng, _, err := image.Decode(bytes.NewBuffer(gopher.GopherPng())) fatal(err) // Now scale it to a reasonable size. gopher := xgraphics.Scale(gopherPng, gopherWidth, gopherHeight) // Create a new xgraphics.Image. It automatically creates an X pixmap for // you, and handles drawing to windows in the XDraw, XPaint and // XSurfaceSet functions. // N.B. An error is possible since X pixmap allocation can fail. canvas := xgraphics.New(X, image.Rect(0, 0, width, height)) // Color in the background color. canvas.For(func(x, y int) xgraphics.BGRA { return bg }) // Use the convenience function XShowExtra to create and map the // canvas window. // XShowExtra will also set the surface window of canvas for us. // We also use XShowExtra to set the name of the window and to quit the // main event loop when the window is closed. win := canvas.XShowExtra("Pointer painting", true) // Listen for pointer motion events and key press events. win.Listen(xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // The mousebind drag function runs three callbacks: one when the drag is // first started, another at each "step" in the drag, and a final one when // the drag is done. // The button sequence (in this case '1') is pressed, the first callback // is executed. If the first return value is true, the drag continues // and a pointer grab is initiated with the cursor id specified in the // second return value (use 0 to keep the cursor unchanged). // If it's false, the drag stops. // Note that Drag will automatically compress MotionNotify events. mousebind.Drag(X, win.Id, win.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawPencil(canvas, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawPencil(canvas, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) mousebind.Drag(X, win.Id, win.Id, "3", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawGopher(canvas, gopher, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawGopher(canvas, gopher, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) // Bind to the clear key specified, and just redraw the bg color. keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { clearCanvas(canvas, win) }).Connect(X, win.Id, clearKey, false) // Bind a callback to each key specified in the 'pencils' color map. // The response is to simply switch the pencil color. for key, clr := range pencils { c := clr keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { log.Printf("Changing pencil color to: %#v", c) pencil = c }).Connect(X, win.Id, key, false) } // Output some basic directions. fmt.Println("Use the left or right buttons on your mouse to paint " + "squares and gophers.") fmt.Println("Pressing numbers 1, 2, 3, 4, 5 or 6 will switch your pencil " + "color.") fmt.Println("Pressing 'c' will clear the canvas.") xevent.Main(X) }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Nice names for the modifier keys (same ones used by xmodmap). // This slice corresponds to the keybind.Modifiers slice (except for // the last 'Any' modifier element). nice := []string{ "shift", "lock", "control", "mod1", "mod2", "mod3", "mod4", "mod5", } // Whenever one uses the keybind package, Initialize should always be // called first. In this case, it initializes the key and modifier maps. keybind.Initialize(X) // Get the current modifier map. // The map is actually a table, where rows correspond to modifiers, and // columns correspond to the keys that activate that modifier. modMap := keybind.ModMapGet(X) // The number of keycodes allowed per modifier (i.e., the number of // columns in the modifier map). kPerMod := int(modMap.KeycodesPerModifier) // Get the number of allowable keysyms per keycode. // This is used to search for a valid keysym for a particular keycode. symsPerKc := int(keybind.KeyMapGet(X).KeysymsPerKeycode) // Imitate everything... fmt.Printf("xmodmap: up to %d keys per modifier, "+ "(keycodes in parentheses):\n\n", kPerMod) // Iterate through all keyboard modifiers defined in xgb/xproto // except the 'Any' modifier (which is last). for mmi := range keybind.Modifiers[:len(keybind.Modifiers)-1] { niceName := nice[mmi] keys := make([]string, 0, kPerMod) // row is the row for the 'mmi' modifier in the modifier mapping table. row := mmi * kPerMod // Iterate over each keycode in the modifier map for this modifier. for _, kc := range modMap.Keycodes[row : row+kPerMod] { // If this entry doesn't have a keycode (i.e., it's zero), we // have to skip it. if kc == 0 { continue } // Look for the first valid keysym in the keyboard map corresponding // to this keycode. If one can't be found, output "BadKey." var ksym xproto.Keysym = 0 for column := 0; column < symsPerKc; column++ { ksym = keybind.KeysymGet(X, kc, byte(column)) if ksym != 0 { break } } if ksym == 0 { keys = append(keys, fmt.Sprintf("BadKey (0x%x)", kc)) } else { keys = append(keys, fmt.Sprintf("%s (0x%x)", keybind.KeysymToStr(ksym), kc)) } } fmt.Printf("%-12s%s\n", niceName, strings.Join(keys, ", ")) } fmt.Println("") }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Anytime the mousebind (keybind) package is used, mousebind.Initialize // *should* be called once. In the case of the mousebind package, this // isn't strictly necessary, but the 'Drag' features of the mousebind // package won't work without it. mousebind.Initialize(X) // Before attaching callbacks, wrap them in a callback function type. // The mouse package exposes two such callback types: // mousebind.ButtonPressFun and mousebind.ButtonReleaseFun. cb1 := mousebind.ButtonPressFun( func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) { log.Println("Button press!") }) // We can now attach the callback to a particular window and button // combination. This particular example grabs a button on the root window, // which makes it a global mouse binding. // Also, "Mod4-1" typically corresponds to pressing down the "Super" or // "Windows" key on your keyboard, and then pressing the left mouse button. // The last two parameters are whether to make a synchronous grab and // whether to actually issue a grab, respectively. // (The parameters used here are the common case.) // See the documentation for the Connect method for more details. err = cb1.Connect(X, X.RootWin(), "Mod4-1", false, true) // A mouse binding can fail if the mouse string could not be parsed, or if // you're trying to bind a button that has already been grabbed by another // client. if err != nil { log.Fatal(err) } // We can even attach multiple callbacks to the same button. err = mousebind.ButtonPressFun( func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) { log.Println("A second handler always happens after the first.") }).Connect(X, X.RootWin(), "Mod4-1", false, true) if err != nil { log.Fatal(err) } // Finally, if we want this client to stop responding to mouse events, we // can attach another handler that, when run, detaches all previous // handlers. // This time, we'll show an example of a ButtonRelease binding. err = mousebind.ButtonReleaseFun( func(X *xgbutil.XUtil, e xevent.ButtonReleaseEvent) { // Use mousebind.Detach to detach the root window // from all ButtonPress *and* ButtonRelease handlers. mousebind.Detach(X, X.RootWin()) mousebind.Detach(X, X.RootWin()) log.Printf("Detached all Button{Press,Release}Events from the "+ "root window (%d).", X.RootWin()) }).Connect(X, X.RootWin(), "Mod4-Shift-1", false, true) if err != nil { log.Fatal(err) } // Finally, start the main event loop. This will route any appropriate // ButtonPressEvents to your callback function. log.Println("Program initialized. Start pressing mouse buttons!") xevent.Main(X) }
func main() { // Connect to the X server using the DISPLAY environment variable. X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Wrap the root window in a nice Window type. root := xwindow.New(X, X.RootWin()) // Get the geometry of the root window. rgeom, err := root.Geometry() if err != nil { log.Fatal(err) } // Get the rectangles for each of the active physical heads. // These are returned sorted in order from left to right and then top // to bottom. // But first check if Xinerama is enabled. If not, use root geometry. var heads xinerama.Heads if X.ExtInitialized("XINERAMA") { heads, err = xinerama.PhysicalHeads(X) if err != nil { log.Fatal(err) } } else { heads = xinerama.Heads{rgeom} } // Fetch the list of top-level client window ids currently managed // by the running window manager. clients, err := ewmh.ClientListGet(X) if err != nil { log.Fatal(err) } // Output the head geometry before modifying them. fmt.Println("Workarea for each head:") for i, head := range heads { fmt.Printf("\tHead #%d: %s\n", i+1, head) } // For each client, check to see if it has struts, and if so, apply // them to our list of head rectangles. for _, clientid := range clients { strut, err := ewmh.WmStrutPartialGet(X, clientid) if err != nil { // no struts for this client continue } // Apply the struts to our heads. // This modifies 'heads' in place. xrect.ApplyStrut(heads, uint(rgeom.Width()), uint(rgeom.Height()), strut.Left, strut.Right, strut.Top, strut.Bottom, strut.LeftStartY, strut.LeftEndY, strut.RightStartY, strut.RightEndY, strut.TopStartX, strut.TopEndX, strut.BottomStartX, strut.BottomEndX) } // Now output the head geometry again after modification. fmt.Println("Workarea for each head after applying struts:") for i, head := range heads { fmt.Printf("\tHead #%d: %s\n", i+1, head) } }