func NewInput(X *xgbutil.XUtil, theme *InputTheme, config InputConfig) *Input { input := &Input{ X: X, theme: theme, config: config, showing: false, do: nil, history: make([]string, 0, 100), } // Create all windows used for the base of the input prompt. cwin := func(p xproto.Window) *xwindow.Window { return xwindow.Must(xwindow.Create(X, p)) } input.win = cwin(X.RootWin()) input.label = cwin(input.win.Id) input.input = text.NewInput(X, input.win.Id, 1000, theme.Padding, theme.Font, theme.FontSize, theme.FontColor, theme.BgColor) input.bInp = cwin(input.win.Id) input.bTop, input.bBot = cwin(input.win.Id), cwin(input.win.Id) input.bLft, input.bRht = cwin(input.win.Id), cwin(input.win.Id) // Make the top-level window override redirect so the window manager // doesn't mess with us. input.win.Change(xproto.CwOverrideRedirect, 1) input.win.Listen(xproto.EventMaskFocusChange) input.input.Listen(xproto.EventMaskKeyPress) // Colorize the windows. cclr := func(w *xwindow.Window, clr render.Color) { w.Change(xproto.CwBackPixel, clr.Uint32()) } cclr(input.win, input.theme.BgColor) cclr(input.bInp, input.theme.BorderColor) cclr(input.bTop, input.theme.BorderColor) cclr(input.bBot, input.theme.BorderColor) cclr(input.bLft, input.theme.BorderColor) cclr(input.bRht, input.theme.BorderColor) // Map the sub-windows once. input.label.Map() input.input.Map() input.bInp.Map() input.bTop.Map() input.bBot.Map() input.bLft.Map() input.bRht.Map() // Connect the key response handler. // The handler is responsible for tab completion and quitting if the // cancel key has been pressed. input.keyResponse().Connect(X, input.input.Id) input.focusResponse().Connect(X, input.win.Id) return input }
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 }
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) }