Example #1
0
// 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
}
Example #2
0
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)
}
Example #3
0
// 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
}
Example #4
0
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
}
Example #5
0
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
}
Example #6
0
// 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
}
Example #7
0
// 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
}
Example #8
0
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
}
Example #9
0
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()
}
Example #10
0
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
}
Example #11
0
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()
}
Example #12
0
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()
}
Example #13
0
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)
}
Example #14
0
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()
}
Example #15
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 #16
0
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")
}
Example #17
0
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
}
Example #18
0
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)
}
Example #19
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 #20
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
}
Example #21
0
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
}