Example #1
0
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)
}
Example #2
0
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)
}
Example #3
0
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)
}
Example #4
0
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
}
Example #5
0
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
		}
	}
}
Example #6
0
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)
	}
}
Example #7
0
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)
}
Example #8
0
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 {}
}
Example #9
0
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)
}
Example #10
0
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("")
}
Example #11
0
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)
}
Example #12
0
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)
	}
}