Example #1
0
// create creates the window, initializes the keybind and mousebind packages
// and sets up the window to act like a real top-level client.
func (w *window) create() {
	keybind.Initialize(w.X)
	mousebind.Initialize(w.X)

	err := w.CreateChecked(w.X.RootWin(), 0, 0, flagWidth, flagHeight,
		xproto.CwBackPixel, 0xffffff)
	if err != nil {
		errLg.Fatalf("Could not create window: %s", err)
	}

	// Make the window close gracefully using the WM_DELETE_WINDOW protocol.
	w.WMGracefulClose(func(w *xwindow.Window) {
		xevent.Detach(w.X, w.Id)
		keybind.Detach(w.X, w.Id)
		mousebind.Detach(w.X, w.Id)
		w.Destroy()
		xevent.Quit(w.X)
	})

	// Set WM_STATE so it is interpreted as top-level and is mapped.
	err = icccm.WmStateSet(w.X, w.Id, &icccm.WmState{
		State: icccm.StateNormal,
	})
	if err != nil { // not a fatal error
		lg("Could not set WM_STATE: %s", err)
	}

	// _NET_WM_STATE = _NET_WM_STATE_NORMAL
	ewmh.WmStateSet(w.X, w.Id, []string{"_NET_WM_STATE_NORMAL"})

	// Set the name to something.
	w.nameSet("Decoding all images...")

	w.Map()
}
Example #2
0
func NewDisplay(width, height, border, heading int, name string) (*Display, error) {
	d := new(Display)
	d.w = float64(width)
	d.h = float64(height)
	d.bord = float64(border)
	d.head = float64(heading)
	X, err := xgbutil.NewConn()
	if err != nil {
		return nil, err
	}
	keybind.Initialize(X)
	d.ximg = xgraphics.New(X, image.Rect(
		0,
		0,
		border*2+width,
		border*2+heading+height))
	err = d.ximg.CreatePixmap()
	if err != nil {
		return nil, err
	}
	painter := NewXimgPainter(d.ximg)
	d.gc = draw2d.NewGraphicContextWithPainter(d.ximg, painter)
	d.gc.Save()
	d.gc.SetStrokeColor(color.White)
	d.gc.SetFillColor(color.White)
	d.gc.Clear()
	d.wid = d.ximg.XShowExtra(name, true)
	d.x = X
	go func() {
		xevent.Main(X)
	}()
	return d, nil
}
Example #3
0
func run() error {
	Xu, err := xgbutil.NewConn()
	if err != nil {
		return err
	}
	defer Xu.Conn().Close()
	keybind.Initialize(Xu)
	if err := randr.Init(Xu.Conn()); err != nil {
		return err
	}

	audio, err := newAudio(Xu)
	if err != nil {
		return err
	}
	defer audio.Close()

	brightness, err := newBrightness(Xu)
	if err != nil {
		return err
	}
	defer brightness.Close()

	xevent.Main(Xu)
	return nil
}
Example #4
0
// NewImage returns a new image canvas
// that draws to the given image.  The
// minimum point of the given image
// should probably be 0,0.
func NewImage(img draw.Image, name string) (*Canvas, error) {
	w := float64(img.Bounds().Max.X - img.Bounds().Min.X)
	h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y)

	X, err := xgbutil.NewConn()
	if err != nil {
		return nil, err
	}
	keybind.Initialize(X)
	ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h)))
	err = ximg.CreatePixmap()
	if err != nil {
		return nil, err
	}
	painter := NewPainter(ximg)
	gc := draw2d.NewGraphicContextWithPainter(ximg, painter)
	gc.SetDPI(dpi)
	gc.Scale(1, -1)
	gc.Translate(0, -h)

	wid := ximg.XShowExtra(name, true)
	go func() {
		xevent.Main(X)
	}()

	c := &Canvas{
		Canvas: vgimg.NewWith(vgimg.UseImageWithContext(img, gc)),
		x:      X,
		ximg:   ximg,
		wid:    wid,
	}
	vg.Initialize(c)
	return c, nil
}
Example #5
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatalln(err)
	}

	// The message box uses the keybind module, so we must initialize it.
	keybind.Initialize(X)

	// Creating a new message prompt is as simple as supply an X connection,
	// a theme and a configuration. We use built in defaults here.
	msgPrompt := prompt.NewMessage(X,
		prompt.DefaultMessageTheme, prompt.DefaultMessageConfig)

	// Show maps the message prompt window.
	// If a duration is specified, the window does NOT acquire focus and
	// automatically disappears after the specified time.
	// If a duration is not specified (i.e., '0'), then the window is mapped,
	// and acquires focus. It does not disappear until it loses focus or when
	// the user hits the "confirm" or "cancel" keys (usually "enter" and
	// "escape").
	timeout := 2 * time.Second // or "0" for no timeout.
	msgPrompt.Show(xwindow.RootGeometry(X), "Hello, world!", timeout, hidden)

	xevent.Main(X)
}
Example #6
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	keybind.Initialize(X) // call once before using keybind package

	// 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.
	win := showImage(ximg, "The Go Gopher!", true)

	// Listen for key press events.
	win.Listen(xproto.EventMaskKeyPress)

	err = keybind.KeyPressFun(
		func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) {
			println("fullscreen!")
			err := ewmh.WmStateReq(X, win.Id, ewmh.StateToggle,
				"_NET_WM_STATE_FULLSCREEN")
			if err != nil {
				log.Fatal(err)
			}
		}).Connect(X, win.Id, "f", false)
	if err != nil {
		log.Fatal(err)
	}

	err = keybind.KeyPressFun(
		func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) {
			println("quit fullscreen!")
			err := ewmh.WmStateReq(X, win.Id, ewmh.StateToggle,
				"_NET_WM_STATE_FULLSCREEN")
			if err != nil {
				log.Fatal(err)
			}
		}).Connect(X, win.Id, "Escape", false)
	if err != nil {
		log.Fatal(err)
	}

	// 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 #7
0
func grabKeyboardAndMouse(m *Manager) {
	if m == nil {
		return
	}

	//go func() {
	X, err := xgbutil.NewConn()
	if err != nil {
		logger.Info("Get New Connection Failed:", err)
		return
	}
	keybind.Initialize(X)
	mousebind.Initialize(X)

	err = keybind.GrabKeyboard(X, X.RootWin())
	if err != nil {
		logger.Info("Grab Keyboard Failed:", err)
		return
	}

	grabAllMouseButton(X)

	xevent.ButtonPressFun(
		func(X *xgbutil.XUtil, e xevent.ButtonPressEvent) {
			dbus.Emit(m, "KeyReleaseEvent", "")
			ungrabAllMouseButton(X)
			keybind.UngrabKeyboard(X)
			logger.Info("Button Press Event")
			xevent.Quit(X)
		}).Connect(X, X.RootWin())

	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			value := parseKeyEnvent(X, e.State, e.Detail)
			pressKeyStr = value
			dbus.Emit(m, "KeyPressEvent", value)
		}).Connect(X, X.RootWin())

	xevent.KeyReleaseFun(
		func(X *xgbutil.XUtil, e xevent.KeyReleaseEvent) {
			if strings.ToLower(pressKeyStr) == "super_l" ||
				strings.ToLower(pressKeyStr) == "super_r" {
				pressKeyStr = "Super"
			}

			dbus.Emit(m, "KeyReleaseEvent", pressKeyStr)
			pressKeyStr = ""
			ungrabAllMouseButton(X)
			keybind.UngrabKeyboard(X)
			logger.Infof("Key: %s\n", pressKeyStr)
			xevent.Quit(X)
		}).Connect(X, X.RootWin())

	xevent.Main(X)
	//}()
}
Example #8
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatalf("Could not connect to X: %v", err)
	}

	keybind.Initialize(X)
	keybind.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			fmt.Println("Key press!")
		}).Connect(X, X.RootWin(), "Mod4-j")

	xevent.Main(X)
}
Example #9
0
func initEGL(controlCh *controlCh, width, height int) *platform.EGLState {
	X, err := xgbutil.NewConn()
	if err != nil {
		panic(err)
	}
	mousebind.Initialize(X)
	keybind.Initialize(X)
	xWindow := newWindow(controlCh, X, width, height)
	go xevent.Main(X)
	return xorg.Initialize(
		egl.NativeWindowType(uintptr(xWindow.Id)),
		xorg.DefaultConfigAttributes,
		xorg.DefaultContextAttributes,
	)
}
Example #10
0
func initXUtil() error {
	var err error

	if X, err = xgbutil.NewConn(); err != nil {
		fmt.Println("New XUtil Failed:", err)
		return err
	}

	if !initFlag {
		keybind.Initialize(X)
		initFlag = true
	}

	return nil
}
Example #11
0
File: main.go Project: dlintw/wingo
func main() {
	X, err := xgbutil.NewConn()
	fatal(err)

	keybind.Initialize(X)

	slct := prompt.NewSelect(X,
		prompt.DefaultSelectTheme, prompt.DefaultSelectConfig)

	// Create some artifical groups to use.
	artGroups := []prompt.SelectGroup{
		slct.NewStaticGroup("Group 1"),
		slct.NewStaticGroup("Group 2"),
		slct.NewStaticGroup("Group 3"),
		slct.NewStaticGroup("Group 4"),
		slct.NewStaticGroup("Group 5"),
	}

	// And now create some artificial items.
	items := []*item{
		newItem("andrew", 1), newItem("bruce", 2),
		newItem("kaitlyn", 3),
		newItem("cauchy", 4), newItem("plato", 1),
		newItem("platonic", 2),
		newItem("andrew gallant", 3),
		newItem("Andrew Gallant", 4), newItem("Andrew", 1),
		newItem("jim", 1), newItem("jimmy", 2),
		newItem("jimbo", 3),
	}

	groups := make([]*prompt.SelectGroupItem, len(artGroups))
	for i, artGroup := range artGroups {
		groups[i] = slct.AddGroup(artGroup)
	}
	for _, item := range items {
		item.promptItem = slct.AddChoice(item)
	}

	geom := headGeom(X)
	keybind.KeyPressFun(
		func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) {
			showGroups := newGroups(groups, items)
			slct.Show(geom, prompt.TabCompletePrefix, showGroups)
		}).Connect(X, X.RootWin(), selectActivate, true)

	println("Loaded...")
	xevent.Main(X)
}
Example #12
0
func main() {
	runtime.GOMAXPROCS(64)

	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	keybind.Initialize(X)

	font := loadFont("/usr/share/fonts/truetype/freefont/FreeMono.ttf")
	font.Color = xgraphics.BGRA{B: 0x00, G: 0xff, R: 0x00, A: 0xff}
	font.Size = 12.0

	ximage := xgraphics.New(X, image.Rect(0, 0, 300, 300))
	ximage.CreatePixmap()
	window, obscured := makeWindow(ximage)

	battery := batteryItem(font, 10, ximage, window)
	cpu := cpuItem(font, 30, ximage, window)
	memory := memoryItem(font, 50, ximage, window)
	before, after, quit := xevent.MainPing(X)
loop:
	for {
		select {
		case <-before:
			<-after
		case <-quit:
			break loop
		case text := <-battery.Text:
			if *obscured {
				continue loop
			}
			battery.update(text)
		case text := <-cpu.Text:
			if *obscured {
				continue loop
			}
			cpu.update(text)
		case text := <-memory.Text:
			if *obscured {
				continue loop
			}
			memory.update(text)
		}
	}
}
Example #13
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 keybind (mousebind) package is used, keybind.Initialize
	// *should* be called once. It isn't strictly necessary, but allows your
	// keybindings to persist even if the keyboard mapping is changed during
	// run-time. (Assuming you're using the xevent package's event loop.)
	// It also handles the case when your modifier map is changed.
	keybind.Initialize(X)

	// Create a new window. We will listen for key presses and translate them
	// only when this window is in focus. (Similar to how `xev` works.)
	win, err := xwindow.Generate(X)
	if err != nil {
		log.Fatalf("Could not generate a new window X id: %s", err)
	}
	win.Create(X.RootWin(), 0, 0, 500, 500, xproto.CwBackPixel, 0xffffffff)

	// Listen for Key{Press,Release} events.
	win.Listen(xproto.EventMaskKeyPress, xproto.EventMaskKeyRelease)

	// Map the window.
	win.Map()

	// Notice that we use xevent.KeyPressFun instead of keybind.KeyPressFun,
	// because we aren't trying to make a grab *and* because we want to listen
	// to *all* key press events, rather than just a particular key sequence
	// that has been pressed.
	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			// keybind.LookupString does the magic of implementing parts of
			// the X Keyboard Encoding to determine an english representation
			// of the modifiers/keycode tuple.
			// N.B. It's working for me, but probably isn't 100% correct in
			// all environments yet.
			log.Println("Key:", keybind.LookupString(X, e.State, e.Detail))
		}).Connect(X, win.Id)

	// Finally, start the main event loop. This will route any appropriate
	// KeyPressEvents to your callback function.
	log.Println("Program initialized. Start pressing keys!")
	xevent.Main(X)
}
Example #14
0
func main() {
	X, _ := xgbutil.NewConn()

	keybind.Initialize(X)

	// should output "{"
	fmt.Println(string(keybind.LookupString(X, 1, 34)))
	// should output "["
	fmt.Println(string(keybind.LookupString(X, 0, 34)))

	fmt.Println("---------------------------------------")

	// should output "A"
	fmt.Println(string(keybind.LookupString(X, 1, 38)))
	// should output "a"
	fmt.Println(string(keybind.LookupString(X, 0, 38)))
}
Example #15
0
func BindKeys(keymap map[string]string) {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}
	keybind.Initialize(X)
	for k, v := range keymap {
		v := v
		err = keybind.KeyPressFun(func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			h.broadcast <- v
		}).Connect(X, X.RootWin(), k, true)
		if err != nil {
			log.Fatal(err)
		}
	}
	log.Println("Program initialized. Start pressing keys!")
	xevent.Main(X)
}
Example #16
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}
	keybind.Initialize(X)

	currentuser, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	configfile := currentuser.HomeDir + "/.config/hotkeys.conf.json"

	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.AddWatch(configfile, inotify.IN_CLOSE_WRITE)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				log.Println(ev)
				err := bindall(configfile, X)
				if err != nil {
					log.Println(err)
					continue
				}

			case err := <-watcher.Error:
				log.Println("error:", err)
			}
		}
	}()
	err = bindall(configfile, X)
	if err != nil {
		log.Panicln(err)
	}
	xevent.Main(X)
}
Example #17
0
func StartKeyBinding() error {
	var err error
	X, err = xgbutil.NewConn()
	if err != nil {
		return err
	}
	keybind.Initialize(X)
	initXRecord()

	initSystemIdDescList()
	//initMediaIdDescList()
	initWindowIdDescList()
	initWorkspaceIdDescList()

	grabKeyPairs(getSystemKeyPairs(), true)
	grabKeyPairs(getCustomKeyPairs(), true)
	grabMediaKeys(true)

	return nil
}
Example #18
0
File: win.go Project: uriel/vimg
// newWindow creates the window, initializes the keybind and mousebind packages
// and sets up the window to act like a real top-level client.
func newWindow(X *xgbutil.XUtil) *Window {
	w, err := xwindow.Generate(X)
	if err != nil {
		errLg.Fatalf("Could not create window: %s", err)
	}

	keybind.Initialize(w.X)
	mousebind.Initialize(w.X)

	err = w.CreateChecked(w.X.RootWin(), 0, 0, 600, 600, xproto.CwBackPixel, 0xffffff)
	if err != nil {
		errLg.Fatalf("Could not create window: %s", err)
	}

	// Make the window close gracefully using the WM_DELETE_WINDOW protocol.
	w.WMGracefulClose(func(w *xwindow.Window) {
		xevent.Detach(w.X, w.Id)
		keybind.Detach(w.X, w.Id)
		mousebind.Detach(w.X, w.Id)
		w.Destroy()
		xevent.Quit(w.X)
	})

	// Set WM_STATE so it is interpreted as top-level and is mapped.
	err = icccm.WmStateSet(w.X, w.Id, &icccm.WmState{State: icccm.StateNormal})
	if err != nil {
		lg("Could not set WM_STATE: %s", err)
	}

	// _NET_WM_STATE = _NET_WM_STATE_NORMAL
	// not needed because we we set FS later anyway?
	//ewmh.WmStateSet(w.X, w.Id, []string{"_NET_WM_STATE_NORMAL"})

	w.Map()

	err = ewmh.WmStateReq(w.X, w.Id, ewmh.StateToggle, "_NET_WM_STATE_FULLSCREEN")
	if err != nil {
		lg("Failed to go FullScreen:", err)
	}
	return &Window{w}
}
Example #19
0
func main() {
	X, err := xgbutil.NewConn()
	fatal(err)

	keybind.Initialize(X)

	cycle := prompt.NewCycle(X,
		prompt.DefaultCycleTheme, prompt.DefaultCycleConfig)

	clients, err := ewmh.ClientListStackingGet(X)
	fatal(err)
	items := make([]*prompt.CycleItem, 0)
	for i := len(clients) - 1; i >= 0; i-- {
		item := cycle.AddChoice(newWindow(X, cycle.Id(), clients[i]))
		items = append(items, item)
	}

	keyHandlers(X, cycle, items)

	println("Loaded...")
	xevent.Main(X)
}
Example #20
0
// NewImage returns a new image canvas
// that draws to the given image.  The
// minimum point of the given image
// should probably be 0,0.
func NewImage(img draw.Image, name string) (*XImgCanvas, error) {
	w := float64(img.Bounds().Max.X - img.Bounds().Min.X)
	h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y)

	X, err := xgbutil.NewConn()
	if err != nil {
		return nil, err
	}
	keybind.Initialize(X)
	ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h)))
	err = ximg.CreatePixmap()
	if err != nil {
		return nil, err
	}
	painter := NewXimgPainter(ximg)
	gc := draw2d.NewGraphicContextWithPainter(ximg, painter)
	gc.SetDPI(dpi)
	gc.Scale(1, -1)
	gc.Translate(0, -h)

	wid := ximg.XShowExtra(name, true)
	go func() {
		xevent.Main(X)
	}()

	c := &XImgCanvas{
		gc:    gc,
		w:     vg.Inches(w / dpi),
		h:     vg.Inches(h / dpi),
		color: []color.Color{color.Black},
		x:     X,
		ximg:  ximg,
		wid:   wid,
	}
	vg.Initialize(c)
	return c, nil
}
Example #21
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatalln(err)
	}

	// The input box uses the keybind module, so we must initialize it.
	keybind.Initialize(X)

	// Creating a new input prompt is as simple as supply an X connection,
	// a theme and a configuration. We use built in defaults here.
	inpPrompt := prompt.NewInput(X,
		prompt.DefaultInputTheme, prompt.DefaultInputConfig)

	// Show maps the input prompt window and sets the focus. It returns
	// immediately, and the main X event loop is started.
	// Also, we use the root window geometry to make sure the prompt is
	// centered in the middle of the screen. 'response' and 'canceled' are
	// callback functions. See their respective commends for more details.
	inpPrompt.Show(xwindow.RootGeometry(X),
		"What is your name?", response, canceled)

	xevent.Main(X)
}
Example #22
0
func main() {
	// Signal Handling.

	sigChan := make(chan os.Signal)

	signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)

	paths := basedir.Paths{
		XDGSuffix:    "gobar",
		GoImportPath: "github.com/AmandaCameron/gobar/data",
	}

	file, err := paths.ConfigFile("config.wini")
	utils.FailMeMaybe(err)

	cfg := loadConfig(file) //os.Getenv("HOME") + "/.config/gobar/config.wini")

	// Load Images.

	images.Init(paths)

	// Setup the X Connection

	X, err := xgbutil.NewConn()
	utils.FailMeMaybe(err)

	win, err := xwindow.Create(X, X.RootWin())
	utils.FailMeMaybe(err)

	win.Resize(cfg.BarWidth, cfg.BarSize)

	// Setup the EWMH Stuff

	utils.FailMeMaybe(ewmh.RestackWindow(X, win.Id))

	var strut *ewmh.WmStrutPartial

	if cfg.Position == "Top" {
		strut = &ewmh.WmStrutPartial{
			Top:       uint(cfg.BarSize),
			TopStartX: 0,
			TopEndX:   uint(cfg.BarWidth),
		}

		win.Move(0, 0)
	} else if cfg.Position == "Bottom" {
		strut = &ewmh.WmStrutPartial{
			Bottom:       uint(cfg.BarSize),
			BottomStartX: 0,
			BottomEndX:   uint(cfg.BarWidth),
		}

		win.Move(0, 600-cfg.BarSize)
	} else {
		println("Invalid Position:", cfg.Position)
		os.Exit(1)
	}

	utils.FailMeMaybe(ewmh.WmStrutPartialSet(X, win.Id, strut))

	utils.FailMeMaybe(ewmh.WmWindowTypeSet(X, win.Id, []string{
		"_NET_WM_WINDOW_TYPE_DOCK",
	}))

	// Put us everywhere.
	utils.FailMeMaybe(ewmh.WmDesktopSet(X, win.Id, 0xFFFFFFFF))

	win.Map()

	keybind.Initialize(X)

	// Get the DE settings, if we can.

	xs, err := xsettings.New(X)
	if err != nil {
		// Maybe this should be an error, maybe not?
		xs = nil
	}

	// Draw the background

	bg := xgraphics.BGRA{
		R: 64,
		G: 64,
		B: 64,
		A: 255,
	}

	img := xgraphics.New(X, image.Rect(0, 0, cfg.BarWidth, cfg.BarSize))

	img.For(func(x, y int) xgraphics.BGRA {
		return bg
	})

	utils.FailMeMaybe(img.XSurfaceSet(win.Id))
	img.XDraw()
	img.XPaint(win.Id)

	// Connect to DBus

	sys, err := dbus.Connect(dbus.SystemBus)
	utils.FailMeMaybe(err)

	// The session bus, too.

	sess, err := dbus.Connect(dbus.SessionBus)
	utils.FailMeMaybe(err)

	// Blah

	x := xdg.New()

	// TODO: How should this fail? I imagine defaulting to gnome is the wrong thing to do,
	// but I'm not really sure what it should do.
	if xs != nil {
		theme, err := xs.GetString("Net/IconThemeName")
		if err == nil {
			x.SetTheme(theme)
		}
	}

	var dev *nm.Device
	var batt *upower.Device

	up := upower.New(sys)
	cli := nm.New(sys)

	if devs, err := cli.GetDevices(); err == nil {
		for _, d := range devs {
			if d.Type() == nm.Wireless {
				dev = d

				break
			}
		}
	}

	if pdevs, err := up.GetDevices(); err == nil {
		for _, d := range pdevs {
			if d.Type() == upower.Battery {
				batt = d
				break
			}
		}
	}

	// Clock

	clck := &Clock{
		X:          X,
		Position:   cfg.Clock.Position,
		Width:      cfg.Clock.Width,
		Height:     cfg.BarSize,
		Parent:     win,
		Format:     cfg.ClockFormat,
		Background: xgraphics.BGRA{R: 48, G: 48, B: 48, A: 255},
		Foreground: xgraphics.BGRA{R: 255, G: 255, B: 255, A: 255},
		Font:       utils.OpenFont(cfg.Clock.Font.Name),
		FontSize:   cfg.Clock.Font.Size,
	}

	clck.Init()

	// App Launch Tracker

	tracker := &Tracker{
		X:          X,
		Position:   cfg.Tracker.Position,
		Size:       cfg.BarSize,
		Background: bg,
		Parent:     win,
	}

	tracker.Init()

	// Command Tray

	ct := &commandtray.CommandTray{
		X:        X,
		Width:    cfg.Command.Width,
		Height:   cfg.BarSize,
		Position: cfg.Command.Position,
		Parent:   win,
		Font:     utils.OpenFont(cfg.Command.Font.Name),
		FontSize: cfg.Command.Font.Size,
	}

	commandtray.Register(commandtray.AppSource{
		Xdg:        x,
		X:          X,
		AppTracker: tracker,
	})

	if sess != nil {
		commandtray.Register(commandtray.GnomeSessionSource{
			Obj: sess.Object("org.gnome.SessionManager", "/org/gnome/SessionManager"),
			Xdg: x,
		})

		commandtray.Register(commandtray.NewShellSource(sess, x))

		commandtray.Register(&commandtray.AppMenuSource{
			Conn: sess,
		})
	}

	// Done, maybe?

	ct.Init()
	ct.Bind(cfg.CommandAccel)
	ct.Draw()

	// Status Bar

	sb := &statbar.StatusBar{
		X:        X,
		Width:    cfg.StatusBar.Width,
		Position: cfg.StatusBar.Position,
		Height:   cfg.BarSize,
		Parent:   win,
	}

	sb.Init()

	if batt != nil {
		sb.Add(&statbar.SbPower{batt})
	}

	if dev != nil {
		sb.Add(&statbar.SbNmWifi{dev})
		commandtray.Register(commandtray.NmSource{dev})
	}

	sb.Draw()

	// My My this anikin guy...

	go func() {
		for {
			select {
			case <-sigChan:
				sb.Teardown()

				time.Sleep(1 * time.Second)
				// Anybody else?
				xevent.Quit(X)
			}
		}
	}()

	xevent.Main(X)
}
Example #23
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Println(err)
		return
	}

	//Initialize the keybind package
	keybind.Initialize(X)

	//Create a window
	win, err := xwindow.Generate(X)
	if err != nil {
		log.Fatalf("Could not generate a new window X id: %s", err)
	}
	win.Create(X.RootWin(), 0, 0, 1024, 768, xproto.CwBackPixel, 0x606060ff)

	// Listen for Key{Press,Release} events.
	win.Listen(xproto.EventMaskKeyPress, xproto.EventMaskKeyRelease)

	// Map the window. This is what makes it on the screen
	win.Map()

	//Make a ...callback... for the events and connect
	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			modStr := keybind.ModifierString(e.State)
			keyStr := keybind.LookupString(X, e.State, e.Detail)
			if len(modStr) > 0 {
				log.Printf("Key: %s-%s\n", modStr, keyStr)
			} else {
				log.Println("Key:", keyStr)
			}

			if keybind.KeyMatch(X, "Escape", e.State, e.Detail) {
				if e.State&xproto.ModMaskControl > 0 {
					log.Println("Control-Escape detected. Quitting...")
					xevent.Quit(X)
				}
			}
		}).Connect(X, win.Id)

	//So here i'm going to try to make a image..'
	img := xgraphics.New(X, image.Rect(0, 0, 1024, 768))

	err = img.XSurfaceSet(win.Id)
	if err != nil {
		log.Printf("Error while setting window surface to image %d: %s\n",
			win, err)
	} else {
		log.Printf("Window %d surface set to image OK\n", win)
	}

	// I /think/ XDraw actually sends data to server?
	img.XDraw()
	// I /think/ XPaint tells the server to paint image to window
	img.XPaint(win.Id)

	//Start the routine that updates the window
	go updater(img, win)

	//This seems to start a main loop for listening to xevents
	xevent.Main(X)
}
Example #24
0
func main() {
	if flagWriteConfig {
		writeConfigFiles()
		os.Exit(0)
	}

	X, err := xgbutil.NewConn()
	if err != nil {
		logger.Error.Println(err)
		logger.Error.Fatalln("Error connecting to X, quitting...")
	}
	defer X.Conn().Close()

	// Do this first! Attempt to retrieve window manager ownership.
	// This includes waiting for any existing window manager to die.
	// 'own' also sets up handlers for quitting when a window manager tries
	// to replace *us*.
	if err := own(X, flagReplace); err != nil {
		logger.Error.Fatalf(
			"Could not establish window manager ownership: %s", err)
	}

	if len(flagConfigDir) > 0 {
		misc.ConfigPaths.Override = flagConfigDir
	}
	if len(flagDataDir) > 0 {
		misc.DataPaths.Override = flagDataDir
	}
	misc.ReadData()

	keybind.Initialize(X)
	mousebind.Initialize(X)
	focus.Initialize(X)
	stack.Initialize(X)
	cursors.Initialize(X)
	wm.Initialize(X, commands.Env, newHacks())
	hook.Initialize(commands.Env, misc.ConfigFile("hooks.wini"))

	// Listen to Root. It is all-important.
	err = xwindow.New(X, X.RootWin()).Listen(
		xproto.EventMaskPropertyChange |
			xproto.EventMaskFocusChange |
			xproto.EventMaskButtonPress |
			xproto.EventMaskButtonRelease |
			xproto.EventMaskStructureNotify |
			xproto.EventMaskSubstructureNotify |
			xproto.EventMaskSubstructureRedirect)
	if err != nil {
		logger.Error.Fatalf("Could not listen to Root window events: %s", err)
	}

	// Update state when the root window changes size
	wm.RootGeomChangeFun().Connect(X, wm.Root.Id)

	// Oblige map request events
	xevent.MapRequestFun(
		func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) {
			xclient.New(ev.Window)
		}).Connect(X, wm.Root.Id)

	// Oblige configure requests from windows we don't manage.
	xevent.ConfigureRequestFun(
		func(X *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) {
			// Make sure we aren't managing this client.
			if wm.FindManagedClient(ev.Window) != nil {
				return
			}

			xwindow.New(X, ev.Window).Configure(int(ev.ValueMask),
				int(ev.X), int(ev.Y), int(ev.Width), int(ev.Height),
				ev.Sibling, ev.StackMode)
		}).Connect(X, wm.Root.Id)

	xevent.FocusInFun(
		func(X *xgbutil.XUtil, ev xevent.FocusInEvent) {
			if ignoreRootFocus(ev.Mode, ev.Detail) {
				return
			}
			if len(wm.Workspace().Clients) == 0 {
				return
			}
			wm.FocusFallback()
		}).Connect(X, wm.Root.Id)

	// Listen to Root client message events. This is how we handle all
	// of the EWMH bullshit.
	xevent.ClientMessageFun(handleClientMessages).Connect(X, wm.Root.Id)

	// Tell everyone what we support.
	setSupported()

	// Start up the IPC command listener.
	go ipc()

	// Just before starting the main event loop, check to see if there are
	// any clients that already exist that we should manage.
	manageExistingClients()

	// Now make sure that clients are in the appropriate visible state.
	for _, wrk := range wm.Heads.Workspaces.Wrks {
		if wrk.IsVisible() {
			wrk.Show()
		} else {
			wrk.Hide()
		}
	}
	wm.Heads.ApplyStruts(wm.Clients)

	wm.FocusFallback()
	wm.Startup = false
	pingBefore, pingAfter, pingQuit := xevent.MainPing(X)

	if len(flagCpuProfile) > 0 {
		f, err := os.Create(flagCpuProfile)
		if err != nil {
			logger.Error.Fatalf("%s\n", err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if flagWingoRestarted {
		hook.Fire(hook.Restarted, hook.Args{})
	} else {
		hook.Fire(hook.Startup, hook.Args{})
	}

EVENTLOOP:
	for {
		select {
		case <-pingBefore:
			// Wait for the event to finish processing.
			<-pingAfter
		case f := <-commands.SafeExec:
			commands.SafeReturn <- f()
		case <-pingQuit:
			break EVENTLOOP
		}
	}
	if wm.Restart {
		// We need to tell the next invocation of Wingo that it is being
		// *restarted*. (So that we don't refire the startup hook.)
		// Thus, search os.Args for "--wingo-restarted". If it doesn't exist,
		// add it.
		found := false
		for _, arg := range os.Args {
			if strings.ToLower(strings.TrimSpace(arg)) == "--wingo-restarted" {
				found = true
			}
		}
		if !found {
			os.Args = append(os.Args, "--wingo-restarted")
		}
		logger.Message.Println("The user has told us to restart...\n\n\n")
		if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil {
			logger.Error.Fatalf("Could not exec '%s': %s",
				strings.Join(os.Args, " "), err)
		}
	}
}
Example #25
0
func main() {
	if flagWriteConfig {
		writeConfigFiles()
		os.Exit(0)
	}

	X, err := xgbutil.NewConn()
	if err != nil {
		logger.Error.Println(err)
		logger.Error.Fatalln("Error connecting to X, quitting...")
	}
	defer X.Conn().Close()

	if flagShowSocket {
		showSocketPath(X)
		return
	}

	// Do this first! Attempt to retrieve window manager ownership.
	// This includes waiting for any existing window manager to die.
	// 'own' also sets up handlers for quitting when a window manager tries
	// to replace *us*.
	if err := own(X, flagReplace); err != nil {
		logger.Error.Fatalf(
			"Could not establish window manager ownership: %s", err)
	}

	if len(flagConfigDir) > 0 {
		misc.ConfigPaths.Override = flagConfigDir
	}
	if len(flagDataDir) > 0 {
		misc.DataPaths.Override = flagDataDir
	}
	misc.ReadData()

	keybind.Initialize(X)
	mousebind.Initialize(X)
	focus.Initialize(X)
	stack.Initialize(X)
	cursors.Initialize(X)
	wm.Initialize(X, commands.Env, newHacks())
	hook.Initialize(commands.Env, misc.ConfigFile("hooks.wini"))

	// Initialize event handlers on the root window.
	rootInit(X)

	// Tell everyone what we support.
	setSupported()

	// Start up the IPC command listener.
	go ipc(X)

	// And start up the IPC event notifier.
	go event.Notifier(X, socketFilePath(X))

	// Just before starting the main event loop, check to see if there are
	// any clients that already exist that we should manage.
	manageExistingClients()

	// Now make sure that clients are in the appropriate visible state.
	for _, wrk := range wm.Heads.Workspaces.Wrks {
		if wrk.IsVisible() {
			wrk.Show()
		} else {
			wrk.Hide()
		}
	}
	wm.Heads.ApplyStruts(wm.Clients)

	wm.FocusFallback()
	wm.Startup = false
	pingBefore, pingAfter, pingQuit := xevent.MainPing(X)

	if len(flagCpuProfile) > 0 {
		f, err := os.Create(flagCpuProfile)
		if err != nil {
			logger.Error.Fatalf("%s\n", err)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	if flagWingoRestarted {
		hook.Fire(hook.Restarted, hook.Args{})
	} else {
		hook.Fire(hook.Startup, hook.Args{})
	}

EVENTLOOP:
	for {
		select {
		case <-pingBefore:
			// Wait for the event to finish processing.
			<-pingAfter
		case f := <-commands.SafeExec:
			commands.SafeReturn <- f()
		case <-pingQuit:
			break EVENTLOOP
		}
	}
	if wm.Restart {
		event.Notify(event.Restarting{})
		for _, client := range wm.Clients {
			c := client.(*xclient.Client)

			if _, ok := c.Frame().(*frame.Full); ok {
				c.FrameNada()
			}
		}
		time.Sleep(1 * time.Second)

		// We need to tell the next invocation of Wingo that it is being
		// *restarted*. (So that we don't refire the startup hook.)
		// Thus, search os.Args for "--wingo-restarted". If it doesn't exist,
		// add it.
		found := false
		for _, arg := range os.Args {
			if strings.ToLower(strings.TrimSpace(arg)) == "--wingo-restarted" {
				found = true
			}
		}
		if !found {
			os.Args = append(os.Args, "--wingo-restarted")
		}
		logger.Message.Println("The user has told us to restart...\n\n\n")
		if err := syscall.Exec(os.Args[0], os.Args, os.Environ()); err != nil {
			logger.Error.Fatalf("Could not exec '%s': %s",
				strings.Join(os.Args, " "), err)
		}
	}
}
Example #26
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 #27
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 keybind (mousebind) package is used, keybind.Initialize
	// *should* be called once. It isn't strictly necessary, but allows your
	// keybindings to persist even if the keyboard mapping is changed during
	// run-time. (Assuming you're using the xevent package's event loop.)
	// It also handles the case when your modifier map is changed.
	keybind.Initialize(X)

	// Create a new window. We will listen for key presses and translate them
	// only when this window is in focus. (Similar to how `xev` works.)
	win, err := xwindow.Generate(X)
	if err != nil {
		log.Fatalf("Could not generate a new window X id: %s", err)
	}
	win.Create(X.RootWin(), 0, 0, 500, 500, xproto.CwBackPixel, 0xffffffff)

	// Listen for Key{Press,Release} events.
	win.Listen(xproto.EventMaskKeyPress, xproto.EventMaskKeyRelease)

	// Map the window.
	win.Map()

	// Notice that we use xevent.KeyPressFun instead of keybind.KeyPressFun,
	// because we aren't trying to make a grab *and* because we want to listen
	// to *all* key press events, rather than just a particular key sequence
	// that has been pressed.
	wid := win.Id
	if flagRoot {
		wid = X.RootWin()
	}
	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, e xevent.KeyPressEvent) {
			// keybind.LookupString does the magic of implementing parts of
			// the X Keyboard Encoding to determine an english representation
			// of the modifiers/keycode tuple.
			// N.B. It's working for me, but probably isn't 100% correct in
			// all environments yet.
			modStr := keybind.ModifierString(e.State)
			keyStr := keybind.LookupString(X, e.State, e.Detail)
			if len(modStr) > 0 {
				log.Printf("Key: %s-%s\n", modStr, keyStr)
			} else {
				log.Println("Key:", keyStr)
			}

			if keybind.KeyMatch(X, "Escape", e.State, e.Detail) {
				if e.State&xproto.ModMaskControl > 0 {
					log.Println("Control-Escape detected. Quitting...")
					xevent.Quit(X)
				}
			}
		}).Connect(X, wid)

	// If we want root, then we take over the entire keyboard.
	if flagRoot {
		if err := keybind.GrabKeyboard(X, X.RootWin()); err != nil {
			log.Fatalf("Could not grab keyboard: %s", err)
		}
		log.Println("WARNING: We are taking *complete* control of the root " +
			"window. The only way out is to press 'Control + Escape' or to " +
			"close the window with the mouse.")
	}

	// Finally, start the main event loop. This will route any appropriate
	// KeyPressEvents to your callback function.
	log.Println("Program initialized. Start pressing keys!")
	xevent.Main(X)
}
Example #28
0
File: main.go Project: mkrull/wingo
func main() {
	X, err := xgbutil.NewConn()
	fatal(err)

	// Remember to always initialize the keybind package before usage.
	keybind.Initialize(X)

	// We create a benign parent window. Its only value in this example is
	// instructional. In particular, it shows how to have a sub-window get
	// focus using the ICCCM WM_TAKE_FOCUS protocol. (Since by default,
	// the window manager will assign focus to your top-level window.)
	// The real magic happens below with the WMTakeFocus method call.
	parentWin, err := xwindow.Create(X, X.RootWin())
	fatal(err)

	// NewInput creates a new input window and handles all of the text drawing
	// for you. It can be any width, but the height will be automatically
	// determined by the height extents of the font size chosen.
	input := text.NewInput(X, parentWin.Id, width, padding, font, fontSize,
		fontColor, bgColor)
	parentWin.Resize(input.Geom.Width(), input.Geom.Height())

	// Make sure X reports KeyPress events when this window is focused.
	input.Listen(xproto.EventMaskKeyPress)

	// Listen to KeyPress events. If it's a BackSpace, remove the last
	// character in the input box. If it's "Return" quit. If it's "Escape",
	// clear the input box.
	// Otherwise, try to add the key pressed to the input box.
	// (Not all key presses correspond to a single character that is added.)
	xevent.KeyPressFun(
		func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) {
			mods, kc := ev.State, ev.Detail
			switch {
			case keybind.KeyMatch(X, "BackSpace", mods, kc):
				input.Remove()
			case keybind.KeyMatch(X, "Return", mods, kc):
				log.Println("Return has been pressed.")
				log.Printf("The current text is: %s", string(input.Text))
				log.Println("Quitting...")
				xevent.Quit(X)
			case keybind.KeyMatch(X, "Escape", mods, kc):
				input.Reset()
			default:
				input.Add(mods, kc)
			}
		}).Connect(X, input.Id)

	// Implement the WM_DELETE_WINDOW protocol.
	parentWin.WMGracefulClose(func(w *xwindow.Window) {
		xevent.Quit(X)
	})

	// Implement the WM_TAKE_FOCUS protocol. The callback function provided
	// is executed when a valid WM_TAKE_FOCUS ClientMessage event has been
	// received from the window manager.
	// According to ICCCM Section 4.2.7, this is one of the three valid ways
	// of setting input focus to a sub-window. (It's also easiest since it
	// doesn't require us to monitor FocusChange events. EW.)
	// If you have multiple sub-windows that can be focused, this callback
	// function is where the logic would go to pick which sub-window should
	// be focused upon receipt of a WM_TAKE_FOCUS message.
	parentWin.WMTakeFocus(func(w *xwindow.Window, tstamp xproto.Timestamp) {
		input.FocusParent(tstamp)
	})

	// Map the window and start the main X event loop.
	input.Map()
	parentWin.Map()
	xevent.Main(X)
}
Example #29
0
File: main.go Project: dlintw/wingo
func main() {
	var err error

	X, err = xgbutil.NewConn()
	if err != nil {
		logger.Error.Println(err)
		logger.Error.Println("Error connecting to X, quitting...")
		return
	}
	defer X.Conn().Close()

	keybind.Initialize(X)
	mousebind.Initialize(X)
	focus.Initialize(X)
	stack.Initialize(X)

	wingo = newWingoState()

	// Create a root window abstraction and load its geometry
	wingo.root = xwindow.New(X, X.RootWin())
	_, err = wingo.root.Geometry()
	if err != nil {
		logger.Error.Println("Could not get ROOT window geometry because: %v",
			err)
		logger.Error.Println("Cannot continue. Quitting...")
		return
	}

	// Load configuration
	wingo.conf, err = loadConfig()
	if err != nil {
		logger.Error.Println(err)
		logger.Error.Println("No configuration found. Quitting...")
		return
	}

	// Load theme
	wingo.theme, err = loadTheme(X)
	if err != nil {
		logger.Error.Println(err)
		logger.Error.Println("No theme configuration found. Quitting...")
		return
	}

	// Initialize prompts
	wingo.prompts = newPrompts()

	wingo.initializeHeads()

	// Attach all global key bindings
	attachAllKeys()

	// Attach all root mouse bindings
	rootMouseConfig()

	// Setup some cursors we use
	cursors.Setup(X)

	// Listen to Root. It is all-important.
	wingo.root.Listen(xproto.EventMaskPropertyChange |
		xproto.EventMaskStructureNotify |
		xproto.EventMaskSubstructureNotify |
		xproto.EventMaskSubstructureRedirect)

	// Update state when the root window changes size
	// xevent.ConfigureNotifyFun(rootGeometryChange).Connect(X, wingo.root.Id)

	// Oblige map request events
	xevent.MapRequestFun(
		func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) {
			newClient(X, ev.Window)
		}).Connect(X, wingo.root.Id)

	// Oblige configure requests from windows we don't manage.
	xevent.ConfigureRequestFun(
		func(X *xgbutil.XUtil, ev xevent.ConfigureRequestEvent) {
			flags := int(ev.ValueMask) &
				^int(xproto.ConfigWindowSibling) &
				^int(xproto.ConfigWindowStackMode)
			xwindow.New(X, ev.Window).Configure(flags,
				int(ev.X), int(ev.Y), int(ev.Width), int(ev.Height),
				ev.Sibling, ev.StackMode)
		}).Connect(X, wingo.root.Id)

	// Listen to Root client message events.
	// We satisfy EWMH with these AND it also provides a mechanism
	// to issue commands using wingo-cmd.
	xevent.ClientMessageFun(commandHandler).Connect(X, wingo.root.Id)

	xevent.Main(X)
}
Example #30
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)
}