// 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 }
func (ct *CommandTray) initPopup() { var err error ct.popup, err = xwindow.Create(ct.X, ct.X.RootWin()) utils.FailMeMaybe(err) ct.pu_img.For(func(x, y int) xgraphics.BGRA { if y%ct.Height == ct.Height-1 || x == 0 || x == ct.Width-1 { return xgraphics.BGRA{128, 128, 128, 255} } return xgraphics.BGRA{64, 64, 64, 255} }) utils.FailMeMaybe(ewmh.WmDesktopSet(ct.X, ct.popup.Id, 0xffffffff)) utils.FailMeMaybe(ewmh.WmWindowTypeSet(ct.X, ct.popup.Id, []string{ "_NET_WM_WINDOW_TYPE_DOCK", })) utils.FailMeMaybe(ct.popup.Listen(xproto.EventMaskKeyPress | xproto.EventMaskStructureNotify)) ct.popup.Resize(ct.Width, ct.Height*10) ct.popup.Move(ct.Position, ct.Height) ct.pu_img.XSurfaceSet(ct.popup.Id) ct.pu_img.XDraw() ct.pu_img.XPaint(ct.popup.Id) }
// 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 (ct *CommandTray) Init() { var err error ct.img = xgraphics.New(ct.X, image.Rect(0, 0, ct.Width, ct.Height)) ct.pu_img = xgraphics.New(ct.X, image.Rect(0, 0, ct.Width, ct.Height*10)) ct.window, err = xwindow.Create(ct.X, ct.Parent.Id) utils.FailMeMaybe(err) utils.FailMeMaybe(ct.img.XSurfaceSet(ct.window.Id)) ct.window.Move(ct.Position, 0) ct.window.Resize(ct.Width, ct.Height) ct.window.Map() }
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 (c *Clock) Init() { var err error c.img = xgraphics.New(c.X, image.Rect(0, 0, c.Width, c.Height)) c.window, err = xwindow.Create(c.X, c.Parent.Id) utils.FailMeMaybe(err) c.window.Resize(c.Width, c.Height) c.window.Move(c.Position, 0) c.img.XSurfaceSet(c.window.Id) c.window.Map() c.Draw() go c.tickTock() }
func (sb *StatusBar) Init() { sb.img = xgraphics.New(sb.X, image.Rect(0, 0, sb.Width, sb.Height)) var err error sb.window, err = xwindow.Create(sb.X, sb.Parent.Id) utils.FailMeMaybe(err) sb.window.Move(sb.Position, 0) sb.window.Resize(sb.Width, sb.Height) sb.window.Map() sb.img.XSurfaceSet(sb.window.Id) utils.FailMeMaybe(sb.initTray()) sb.Draw() }
func main() { X, err := xgbutil.NewConn() failMeMaybe(err) tray, err := NewSystemTray(X) failMeMaybe(err) hdlr := &Handler{ X: X, } hdlr.Window, err = xwindow.Create(X, X.RootWin()) failMeMaybe(err) hdlr.Window.Move(0, 24) hdlr.Window.Map() tray.Handler = hdlr xevent.Main(X) }
func (t *Tracker) Init() { var err error t.img = xgraphics.New(t.X, image.Rect(0, 0, t.Size, t.Size)) t.window, err = xwindow.Create(t.X, t.Parent.Id) utils.FailMeMaybe(err) t.window.Resize(t.Size, t.Size) t.window.Move(t.Position, 0) t.img.XSurfaceSet(t.window.Id) t.window.Map() t.stopMe = true l := startup.Listener{ X: t.X, Callbacks: t, } l.Initialize() t.Draw() }
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) }
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") }
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 xwmInit(fd uintptr) { X := fromFd(fd) defer X.Conn().Close() root := xwindow.New(X, X.RootWin()) if _, err := root.Geometry(); err != nil { panic(err) } // if names, _ := ewmh.DesktopNamesGet(X); len(names) > 0 { // println(names) // } composite.Init(X.Conn()) atomNames := []string{ "WL_SURFACE_ID", "WM_DELETE_WINDOW", "WM_PROTOCOLS", "WM_S0", "WM_NORMAL_HINTS", "WM_TAKE_FOCUS", "WM_STATE", "WM_CLIENT_MACHINE", "_NET_WM_CM_S0", "_NET_WM_NAME", "_NET_WM_PID", "_NET_WM_ICON", "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_USER_TIME", "_NET_WM_ICON_NAME", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_WINDOW_TYPE_DOCK", "_NET_WM_WINDOW_TYPE_TOOLBAR", "_NET_WM_WINDOW_TYPE_MENU", "_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_SPLASH", "_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", "_NET_WM_WINDOW_TYPE_POPUP_MENU", "_NET_WM_WINDOW_TYPE_TOOLTIP", "_NET_WM_WINDOW_TYPE_NOTIFICATION", "_NET_WM_WINDOW_TYPE_COMBO", "_NET_WM_WINDOW_TYPE_DND", "_NET_WM_WINDOW_TYPE_NORMAL", "_NET_WM_MOVERESIZE", "_NET_SUPPORTING_WM_CHECK", "_NET_SUPPORTED", "_MOTIF_WM_HINTS", "CLIPBOARD", "CLIPBOARD_MANAGER", "TARGETS", "UTF8_STRING", "_WL_SELECTION", "INCR", "TIMESTAMP", "MULTIPLE", "UTF8_STRING", "COMPOUND_TEXT", "TEXT", "STRING", "text/plain;charset=utf-8", "text/plain", "XdndSelection", "XdndAware", "XdndEnter", "XdndLeave", "XdndDrop", "XdndStatus", "XdndFinished", "XdndTypeList", "XdndActionCopy", } cookies := make([]xproto.InternAtomCookie, len(atomNames)) for i := 0; i < len(atomNames); i++ { cookies[i] = xproto.InternAtom(X.Conn(), false, uint16(len(atomNames[i])), atomNames[i]) } /* Try to select for substructure redirect. */ evMasks := xproto.EventMaskPropertyChange | xproto.EventMaskFocusChange | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskStructureNotify | xproto.EventMaskSubstructureNotify | xproto.EventMaskSubstructureRedirect root.Listen(evMasks) composite.RedirectSubwindows(X.Conn(), root.Id, composite.RedirectManual) // change config // data := []byte{1} // propAtom, _ := xprop.Atm(X, "_NET_SUPPORTED") // var format byte = 32 // xproto.ChangePropertyChecked(X.Conn(), xproto.PropModeReplace, // root.Id, propAtom, xproto.AtomAtom, format, // uint32(len(data)/(int(format)/8)), data) ewmh.SupportedSet(X, []string{ "_NET_SUPPORTED", "_NET_CLIENT_LIST", "_NET_NUMBER_OF_DESKTOPS", "_NET_DESKTOP_GEOMETRY", "_NET_CURRENT_DESKTOP", "_NET_VISIBLE_DESKTOPS", "_NET_DESKTOP_NAMES", "_NET_ACTIVE_WINDOW", "_NET_SUPPORTING_WM_CHECK", "_NET_CLOSE_WINDOW", "_NET_MOVERESIZE_WINDOW", "_NET_RESTACK_WINDOW", "_NET_WM_NAME", "_NET_WM_DESKTOP", "_NET_WM_WINDOW_TYPE", "_NET_WM_WINDOW_TYPE_DESKTOP", "_NET_WM_WINDOW_TYPE_DOCK", "_NET_WM_WINDOW_TYPE_TOOLBAR", "_NET_WM_WINDOW_TYPE_MENU", "_NET_WM_WINDOW_TYPE_UTILITY", "_NET_WM_WINDOW_TYPE_SPLASH", "_NET_WM_WINDOW_TYPE_DIALOG", "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", "_NET_WM_WINDOW_TYPE_POPUP_MENU", "_NET_WM_WINDOW_TYPE_TOOLTIP", "_NET_WM_WINDOW_TYPE_NOTIFICATION", "_NET_WM_WINDOW_TYPE_COMBO", "_NET_WM_WINDOW_TYPE_DND", "_NET_WM_WINDOW_TYPE_NORMAL", "_NET_WM_STATE", "_NET_WM_STATE_STICKY", "_NET_WM_STATE_MAXIMIZED_VERT", "_NET_WM_STATE_MAXIMIZED_HORZ", "_NET_WM_STATE_SKIP_TASKBAR", "_NET_WM_STATE_SKIP_PAGER", "_NET_WM_STATE_HIDDEN", "_NET_WM_STATE_FULLSCREEN", "_NET_WM_STATE_ABOVE", "_NET_WM_STATE_BELOW", "_NET_WM_STATE_DEMANDS_ATTENTION", "_NET_WM_STATE_FOCUSED", "_NET_WM_ALLOWED_ACTIONS", "_NET_WM_ACTION_MOVE", "_NET_WM_ACTION_RESIZE", "_NET_WM_ACTION_MINIMIZE", "_NET_WM_ACTION_STICK", "_NET_WM_ACTION_MAXIMIZE_HORZ", "_NET_WM_ACTION_MAXIMIZE_VERT", "_NET_WM_ACTION_FULLSCREEN", "_NET_WM_ACTION_CHANGE_DESKTOP", "_NET_WM_ACTION_CLOSE", "_NET_WM_ACTION_ABOVE", "_NET_AM_ACTION_BELOW", "_NET_WM_STRUT_PARTIAL", "_NET_WM_ICON", "_NET_FRAME_EXTENTS", "WM_TRANSIENT_FOR", }) // create wm window win, _ := xwindow.Create(X, root.Id) xproto.MapWindow(X.Conn(), win.Id) atomValues := make([]xproto.Atom, len(atomNames)) for num, cookie := range cookies { reply, _ := cookie.Reply() atomValues[num] = reply.Atom } /* take WM_S0 selection last, which * signals to Xwayland that we're done with setup. */ xproto.SetSelectionOwner(X.Conn(), win.Id, atomValues[3], xproto.TimeCurrentTime, ) mapResquest := func(event xgb.Event) { ev, _ := event.(xproto.MapRequestEvent) log.Info("MapRequest: ", ev) xproto.MapWindow(X.Conn(), ev.Window) icccm.WmStateSet(X, ev.Window, &icccm.WmState{ State: icccm.StateNormal, Icon: ev.Window, }) // TODO: set _net_wm_state } for { x := X.Conn() ev, xerr := x.WaitForEvent() if ev == nil && xerr == nil { fmt.Println("Both event and error are nil. Exiting...") return } // if ev != nil { // fmt.Printf("Event: %s\n", ev) // } if xerr != nil { fmt.Printf("Error: %s\n", xerr) } switch ev.(type) { case xproto.CreateNotifyEvent: createNotify(X, ev) fmt.Printf("Event: %s\n", ev) case xproto.DestroyNotifyEvent: destroyNotify(X, ev) fmt.Printf("Event: %s\n", ev) case xproto.MapRequestEvent: mapResquest(ev) case xproto.ConfigureNotifyEvent: configureNotify(X, ev) case xproto.PropertyNotifyEvent: fmt.Printf("Event: %s\n", ev) case xproto.ClientMessageEvent: clientMessage(X, ev) case xproto.ConfigureRequestEvent: configureRequest(X, ev) case xproto.UnmapNotifyEvent: unmapNotify(X, ev) default: log.Info("Event:", ev) } } // xevent.MapRequestFun( // func(X *xgbutil.XUtil, e xevent.MapRequestEvent) { // println(e.Window) // }).Connect(X, root.Id) // xevent.ConfigureNotifyFun( // func(X *xgbutil.XUtil, e xevent.ConfigureNotifyEvent) { // fmt.Printf("(%d, %d) %dx%d\n", e.X, e.Y, e.Width, e.Height) // }).Connect(X, root.Id) // xevent.FocusInFun( // func(X *xgbutil.XUtil, e xevent.FocusInEvent) { // fmt.Printf("(%v, %v)\n", e.Mode, e.Detail) // }).Connect(X, root.Id) // xevent.Main(X) }
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) }
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 New(X *xgbutil.XUtil) (*SystemTray, error) { tray := &SystemTray{ X: X, } var err error if sysTrayAtom == 0 { sysTrayAtom, err = xprop.Atom(X, "_NET_SYSTEM_TRAY_S0", false) if err != nil { return nil, err } } if sysTrayMsgAtom == 0 { sysTrayMsgAtom, err = xprop.Atom(X, "_NET_SYSTEM_TRAY_OPCODE", false) if err != nil { return nil, err } } if managerEventAtom == 0 { managerEventAtom, err = xprop.Atom(X, "MANAGER", false) if err != nil { return nil, err } } tray.wid, err = xwindow.Create(X, X.RootWin()) if err != nil { return nil, err } ts, err := currentTime(X) if err != nil { return nil, err } X.TimeSet(ts) // tray.wid.Listen(xproto.EventMaskNoEvent | xproto.EventMaskPropertyChange) err = xproto.SetSelectionOwnerChecked(tray.X.Conn(), tray.wid.Id, sysTrayAtom, tray.X.TimeGet()).Check() if err != nil { return nil, err } reply, err := xproto.GetSelectionOwner(X.Conn(), sysTrayAtom).Reply() if err != nil { return nil, err } if reply.Owner != tray.wid.Id { return nil, fmt.Errorf("Could not get ownership of the thingy-thing.") } evt, err := xevent.NewClientMessage(32, X.RootWin(), managerEventAtom, int(X.TimeGet()), int(sysTrayAtom), int(tray.wid.Id)) if err != nil { return nil, err } if err = xevent.SendRootEvent(X, evt, xproto.EventMaskStructureNotify); err != nil { return nil, err } xevent.ClientMessageFun(func(_ *xgbutil.XUtil, ev xevent.ClientMessageEvent) { tray.event(ev) }).Connect(tray.X, tray.wid.Id) return tray, nil }