// newCycleItem sets up the windows and images associated with a particular // CycleChoice. This is the meat of (*Cycle).AddItem. func newCycleItem(cycle *Cycle, choice CycleChoice) *CycleItem { ci := &CycleItem{ cycle: cycle, choice: choice, } t := ci.cycle.theme ci.win = xwindow.Must(xwindow.Create(ci.cycle.X, ci.cycle.win.Id)) ci.active = xwindow.Must(xwindow.Create(ci.cycle.X, ci.win.Id)) ci.inactive = xwindow.Must(xwindow.Create(ci.cycle.X, ci.win.Id)) ci.text = xwindow.Must(xwindow.Create(ci.cycle.X, ci.cycle.win.Id)) ci.active.MoveResize(t.IconBorderSize, t.IconBorderSize, t.IconSize, t.IconSize) ci.inactive.MoveResize(t.IconBorderSize, t.IconBorderSize, t.IconSize, t.IconSize) ci.text.MoveResize(t.BorderSize+t.Padding, t.BorderSize+t.Padding, 1, 1) // If the text overruns, make sure it's below the borders. ci.text.StackSibling(ci.cycle.bRht.Id, xproto.StackModeBelow) ci.UpdateImage() ci.UpdateText() ci.unhighlight() return ci }
// NewInput constructs Input values. It needs an X connection, a parent window, // the width of the input box, and theme information related for the font // and background. Padding separating the text and the edges of the window // may also be specified. // // While NewInput returns an *Input, a Input value also has an xwindow.Window // value embedded into it. Thus, an Input can also be treated as a normal // window on which you can assign callbacks, close, destroy, etc. // // As with all windows, the Input window should be destroyed when it is no // longer in used. func NewInput(X *xgbutil.XUtil, parent xproto.Window, width int, padding int, font *truetype.Font, fontSize float64, fontColor, bgColor render.Color) *Input { _, height := xgraphics.TextMaxExtents(font, fontSize, "M") height += misc.TextBreathe width, height = width+2*padding, height+2*padding img := xgraphics.New(X, image.Rect(0, 0, width, height)) win := xwindow.Must(xwindow.Create(X, parent)) win.Listen(xproto.EventMaskKeyPress) win.Resize(width, height) ti := &Input{ Window: win, img: img, Text: make([]rune, 0, 50), font: font, fontSize: fontSize, fontColor: fontColor, bgColor: bgColor, padding: padding, } ti.Render() return ti }
func newSelectItem(slct *Select, choice SelectChoice) *SelectItem { si := &SelectItem{ slct: slct, choice: choice, } si.regular = xwindow.Must(xwindow.Create(si.slct.X, si.slct.win.Id)) si.highlighted = xwindow.Must(xwindow.Create(si.slct.X, si.slct.win.Id)) // If the text overruns, make sure it's below the borders. si.regular.StackSibling(si.slct.bRht.Id, xproto.StackModeBelow) si.highlighted.StackSibling(si.slct.bRht.Id, xproto.StackModeBelow) si.UpdateText() return si }
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 }
// Window is a convenience function for painting the provided // Image value to a new window, destroying the pixmap created by that image, // and returning the window value. // The window is sized to the dimensions of the image. func (im *Image) Window(parent xproto.Window) *xwindow.Window { win := xwindow.Must(xwindow.Create(im.X, parent)) win.Resize(im.Bounds().Dx(), im.Bounds().Dy()) im.XSurfaceSet(win.Id) im.XDraw() im.XPaint(win.Id) im.Destroy() return win }
// NewCycle creates a new prompt. As many prompts as you want can be created, // and they could even technically be shown simultaneously so long as at most // one of them is using a grab. (The grab will fail for the others and they // will not be shown.) // // CycleTheme and CycleConfig values can either use DefaultCycle{Theme,Config} // values found in this package, or custom ones can be created using // composite literals. func NewCycle(X *xgbutil.XUtil, theme *CycleTheme, config CycleConfig) *Cycle { cycle := &Cycle{ X: X, theme: theme, config: config, showing: false, selected: -1, grabMods: 0, } // Create all windows used for the base of the cycle prompt. // This obviously doesn't include the windows representing the items. cwin := func(p xproto.Window) *xwindow.Window { return xwindow.Must(xwindow.Create(X, p)) } cycle.win = cwin(X.RootWin()) cycle.bTop, cycle.bBot = cwin(cycle.win.Id), cwin(cycle.win.Id) cycle.bLft, cycle.bRht = cwin(cycle.win.Id), cwin(cycle.win.Id) // Make the top-level window override redirect so the window manager // doesn't mess with us. cycle.win.Change(xproto.CwOverrideRedirect, 1) // Set the colors of each window. cclr := func(w *xwindow.Window, clr render.Color) { w.Change(xproto.CwBackPixel, uint32(clr.Int())) } cclr(cycle.win, cycle.theme.BgColor) cclr(cycle.bTop, cycle.theme.BorderColor) cclr(cycle.bBot, cycle.theme.BorderColor) cclr(cycle.bLft, cycle.theme.BorderColor) cclr(cycle.bRht, cycle.theme.BorderColor) // Map the sub-windows once. (Real mapping only happens when // cycle.win is mapped.) cycle.bTop.Map() cycle.bBot.Map() cycle.bLft.Map() cycle.bRht.Map() // Connect the key response handler (i.e., the alt-tab'ing, canceling, etc.) cycle.keyResponse().Connect(X, X.Dummy()) // Guess the maximum font height. _, cycle.fontHeight = xgraphics.TextMaxExtents( cycle.theme.Font, cycle.theme.FontSize, "A") cycle.fontHeight += misc.TextBreathe return cycle }
func NewMessage(X *xgbutil.XUtil, theme *MessageTheme, config MessageConfig) *Message { msg := &Message{ X: X, theme: theme, config: config, showing: false, duration: 0, hidden: nil, cancelTimeout: make(chan struct{}, 0), textWins: make([]*xwindow.Window, 0), } // Create all windows used for the base of the message prompt. cwin := func(p xproto.Window) *xwindow.Window { return xwindow.Must(xwindow.Create(X, p)) } msg.win = cwin(X.RootWin()) msg.bTop, msg.bBot = cwin(msg.win.Id), cwin(msg.win.Id) msg.bLft, msg.bRht = cwin(msg.win.Id), cwin(msg.win.Id) // Make the top-level window override redirect so the window manager // doesn't mess with us. msg.win.Change(xproto.CwOverrideRedirect, 1) msg.win.Listen(xproto.EventMaskFocusChange) msg.bTop.Listen(xproto.EventMaskKeyPress) // Colorize the windows. cclr := func(w *xwindow.Window, clr render.Color) { w.Change(xproto.CwBackPixel, clr.Uint32()) } cclr(msg.win, msg.theme.BgColor) cclr(msg.bTop, msg.theme.BorderColor) cclr(msg.bBot, msg.theme.BorderColor) cclr(msg.bLft, msg.theme.BorderColor) cclr(msg.bRht, msg.theme.BorderColor) // Map the sub-windows once. msg.bTop.Map() msg.bBot.Map() msg.bLft.Map() msg.bRht.Map() msg.keyResponse().Connect(X, msg.bTop.Id) msg.focusResponse().Connect(X, msg.win.Id) return msg }
func newSelectGroupItem(slct *Select, group SelectGroup) *SelectGroupItem { si := &SelectGroupItem{ slct: slct, group: group, } si.win = xwindow.Must(xwindow.Create(si.slct.X, si.slct.win.Id)) si.win.Change(xproto.CwBackPixel, si.slct.theme.BgColor.Uint32()) // If the text overruns, make sure it's below the borders. si.win.StackSibling(si.slct.bRht.Id, xproto.StackModeBelow) si.UpdateText() return si }
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 (msg *Message) Show(workarea xrect.Rect, message string, duration time.Duration, hidden func(msg *Message)) bool { if msg.showing { return false } msg.win.Stack(xproto.StackModeAbove) pad, bs := msg.theme.Padding, msg.theme.BorderSize height := pad + bs width := 0 for _, line := range strings.Split(strings.TrimSpace(message), "\n") { textWin := xwindow.Must(xwindow.Create(msg.X, msg.win.Id)) msg.textWins = append(msg.textWins, textWin) if len(line) == 0 { line = " " } textWin.Map() textWin.Move(bs+pad, height) text.DrawText(textWin, msg.theme.Font, msg.theme.FontSize, msg.theme.FontColor, msg.theme.BgColor, line) height += textWin.Geom.Height() if w := textWin.Geom.Width(); w > width { width = w } } height += pad + bs width += pad*2 + bs*2 // position the damn window based on its width/height (i.e., center it) posx := workarea.X() + workarea.Width()/2 - width/2 posy := workarea.Y() + workarea.Height()/2 - height/2 msg.win.MoveResize(posx, posy, width, height) msg.bTop.Resize(width, bs) msg.bBot.MoveResize(0, height-bs, width, bs) msg.bLft.Resize(bs, height) msg.bRht.MoveResize(width-bs, 0, bs, height) msg.showing = true msg.duration = duration msg.hidden = hidden msg.win.Map() msg.lastShow = time.Now() // If the duration is non-zero, then wait for that amount of time and // automatically hide the popup. Otherwise, focus the window and wait // for user interaction. if duration == 0 { msg.bTop.Focus() } else { go func() { // If `Hide` is called before the timeout expires, we'll // cancel the timeout. select { case <-time.After(duration): msg.Hide() case <-msg.cancelTimeout: } }() } return true }
func (wingo *wingoState) ewmhSupportingWmCheck() { supportingWin := xwindow.Must(xwindow.Create(X, wingo.root.Id)) ewmh.SupportingWmCheckSet(X, wingo.root.Id, supportingWin.Id) ewmh.SupportingWmCheckSet(X, supportingWin.Id, supportingWin.Id) ewmh.WmNameSet(X, supportingWin.Id, "Wingo") }