Beispiel #1
0
func newWindow(X *xgbutil.XUtil) {
	win, err := xwindow.Generate(X)
	if err != nil {
		log.Fatal(err)
	}
	win.Create(X.RootWin(), 0, 0, 200, 200,
		xproto.CwBackPixel|xproto.CwEventMask,
		0, xproto.EventMaskButtonRelease)
	win.WMGracefulClose(
		func(w *xwindow.Window) {
			xevent.Detach(w.X, w.Id)
			mousebind.Detach(w.X, w.Id)
			w.Destroy()
			xevent.Quit(X)
			Done <- true
		})

	win.Map()

	err = mousebind.ButtonReleaseFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
			newWindow(X)
		}).Connect(X, win.Id, "1", false, false)

	if err != nil {
		log.Fatal(err)
	}
}
Beispiel #2
0
func (mcmd mouseCommand) attachClick(wid xproto.Window, run func()) {
	mousebind.ButtonPressFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonPressEvent) {
			// empty
		}).Connect(X, wid, mcmd.buttonStr, false, true)
	mousebind.ButtonReleaseFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
			run()
		}).Connect(X, wid, mcmd.buttonStr, false, false)
}
Beispiel #3
0
// newWindow creates a new window with a random background color. It sets the
// WM_PROTOCOLS property to contain the WM_DELETE_WINDOW atom. It also sets
// up a ClientMessage event handler so that we know when to destroy the window.
// We also set up a mouse binding so that clicking inside a window will
// create another one.
func newWindow(X *xgbutil.XUtil) {
	counter++
	win, err := xwindow.Generate(X)
	if err != nil {
		log.Fatal(err)
	}

	// Get a random background color, create the window (ask to receive button
	// release events while we're at it) and map the window.
	bgColor := rand.Intn(0xffffff + 1)
	win.Create(X.RootWin(), 0, 0, 200, 200,
		xproto.CwBackPixel|xproto.CwEventMask,
		uint32(bgColor), xproto.EventMaskButtonRelease)

	// WMGracefulClose does all of the work for us. It sets the appropriate
	// values for WM_PROTOCOLS, and listens for ClientMessages that implement
	// the WM_DELETE_WINDOW protocol. When one is found, the provided callback
	// is executed.
	win.WMGracefulClose(
		func(w *xwindow.Window) {
			// Detach all event handlers.
			// This should always be done when a window can no longer
			// receive events.
			xevent.Detach(w.X, w.Id)
			mousebind.Detach(w.X, w.Id)
			w.Destroy()

			// Exit if there are no more windows left.
			counter--
			if counter == 0 {
				os.Exit(0)
			}
		})

	// It's important that the map comes after setting WMGracefulClose, since
	// the WM isn't obliged to watch updates to the WM_PROTOCOLS property.
	win.Map()

	// A mouse binding so that a left click will spawn a new window.
	// Note that we don't issue a grab here. Typically, window managers will
	// grab a button press on the client window (which usually activates the
	// window), so that we'd end up competing with the window manager if we
	// tried to grab it.
	// Instead, we set a ButtonRelease mask when creating the window and attach
	// a mouse binding *without* a grab.
	err = mousebind.ButtonReleaseFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
			newWindow(X)
		}).Connect(X, win.Id, "1", false, false)
	if err != nil {
		log.Fatal(err)
	}
}
Beispiel #4
0
func (mcmd mouseCommand) attach(wid xproto.Window, run func(),
	propagate, grab bool) {

	if mcmd.down {
		mousebind.ButtonPressFun(
			func(X *xgbutil.XUtil, ev xevent.ButtonPressEvent) {
				run()
			}).Connect(X, wid, mcmd.buttonStr, propagate, grab)
	} else {
		mousebind.ButtonReleaseFun(
			func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
				run()
			}).Connect(X, wid, mcmd.buttonStr, propagate, grab)
	}
}
Beispiel #5
0
// attachGrabRelease is a special case of 'attach' that is necessary when
// attaching a mouse release event to either the client or frame window.
//
// TODO: Recall and document *why* this is needed.
func (mcmd mouseCommand) attachGrabRelease(wid xproto.Window, run func()) {
	var err error

	err = mousebind.ButtonPressFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonPressEvent) {
			// empty
		}).Connect(X, wid, mcmd.buttonStr, false, true)
	if err != nil {
		logger.Warning.Printf("Could not bind '%s': %s", mcmd.buttonStr, err)
	}

	err = mousebind.ButtonReleaseFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
			run()
		}).Connect(X, wid, mcmd.buttonStr, false, false)
	if err != nil {
		logger.Warning.Printf("Could not bind '%s': %s", mcmd.buttonStr, err)
	}
}
Beispiel #6
0
// attach sets up the event handlers for a mouse button press OR release.
func (mcmd mouseCommand) attach(wid xproto.Window, run func(),
	propagate, grab bool) {

	if mcmd.down {
		err := mousebind.ButtonPressFun(
			func(X *xgbutil.XUtil, ev xevent.ButtonPressEvent) {
				run()
			}).Connect(X, wid, mcmd.buttonStr, propagate, grab)
		if err != nil {
			logger.Warning.Printf("Could not bind '%s': %s",
				mcmd.buttonStr, err)
		}
	} else {
		err := mousebind.ButtonReleaseFun(
			func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
				run()
			}).Connect(X, wid, mcmd.buttonStr, propagate, grab)
		if err != nil {
			logger.Warning.Printf("Could not bind '%s': %s",
				mcmd.buttonStr, err)
		}
	}
}
Beispiel #7
0
func NewSelect(X *xgbutil.XUtil,
	theme *SelectTheme, config SelectConfig) *Select {

	slct := &Select{
		X:           X,
		theme:       theme,
		config:      config,
		showing:     false,
		selected:    -1,
		tabComplete: TabCompletePrefix,
	}

	// Create all windows used for the base of the select prompt. This
	// obviously doesn't include the windows representing the items/groups.
	cwin := func(p xproto.Window) *xwindow.Window {
		return xwindow.Must(xwindow.Create(X, p))
	}
	slct.win = cwin(X.RootWin())
	slct.bInp = cwin(slct.win.Id)
	slct.bTop, slct.bBot = cwin(slct.win.Id), cwin(slct.win.Id)
	slct.bLft, slct.bRht = cwin(slct.win.Id), cwin(slct.win.Id)

	// Make the top-level window override redirect so the window manager
	// doesn't mess with us.
	slct.win.Change(xproto.CwOverrideRedirect, 1)
	slct.win.Listen(xproto.EventMaskFocusChange)
	slct.bInp.Listen(xproto.EventMaskKeyPress)

	// Create the text input window.
	slct.input = text.NewInput(X, slct.win.Id, 1000, 10,
		slct.theme.Font, slct.theme.FontSize,
		slct.theme.FontColor, slct.theme.BgColor)
	slct.input.Move(slct.theme.BorderSize, slct.theme.BorderSize)
	slct.input.StackSibling(slct.bRht.Id, xproto.StackModeBelow)

	// Colorize the windows.
	cclr := func(w *xwindow.Window, clr render.Color) {
		w.Change(xproto.CwBackPixel, clr.Uint32())
	}
	cclr(slct.win, slct.theme.BgColor)
	cclr(slct.bInp, slct.theme.BorderColor)
	cclr(slct.bTop, slct.theme.BorderColor)
	cclr(slct.bBot, slct.theme.BorderColor)
	cclr(slct.bLft, slct.theme.BorderColor)
	cclr(slct.bRht, slct.theme.BorderColor)

	// Map the sub-windows once. (Real mapping only happens when
	// cycle.win is mapped.)
	slct.bInp.Map()
	slct.bTop.Map()
	slct.bBot.Map()
	slct.bLft.Map()
	slct.bRht.Map()
	slct.input.Map()

	// Connect the key response handler.
	// The handler is responsible for tab completion and quitting if the
	// cancel key has been pressed.
	slct.keyResponse().Connect(X, slct.bInp.Id)
	slct.focusResponse().Connect(X, slct.win.Id)

	// Attach a mouse handler so the user can re-focus the prompt window.
	mousebind.ButtonReleaseFun(
		func(X *xgbutil.XUtil, ev xevent.ButtonReleaseEvent) {
			slct.win.Focus()
		}).Connect(X, slct.win.Id, "1", false, true)

	return slct
}
Beispiel #8
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)
}