Cache application icons
parent
1bb42b05cc
commit
c1cfe822b0
|
@ -6,30 +6,30 @@ import (
|
|||
"html"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gotk3/gotk3/pango"
|
||||
|
||||
"git.sr.ht/~tslocum/desktop"
|
||||
"git.sr.ht/~tslocum/gmenu/pkg/gmenu"
|
||||
"github.com/gotk3/gotk3/gdk"
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
"github.com/gotk3/gotk3/pango"
|
||||
"github.com/kballard/go-shellquote"
|
||||
"github.com/tslocum/gotk3/gtk"
|
||||
gtkfork "github.com/tslocum/gotk3/gtk"
|
||||
)
|
||||
|
||||
const (
|
||||
iconSize = 48
|
||||
iconMargin = 4
|
||||
iconMarginStart = 2
|
||||
labelMarginStart = 4
|
||||
iconMarginStart = 4
|
||||
labelMarginStart = 8
|
||||
labelMarginTop = 8
|
||||
labelMarginTopComment = 4
|
||||
)
|
||||
|
||||
var execLabel *gtk.Label
|
||||
var (
|
||||
execLabel *gtk.Label
|
||||
)
|
||||
|
||||
func initList(container *gtk.Box) {
|
||||
inputView = newTextView()
|
||||
|
@ -60,8 +60,9 @@ func initList(container *gtk.Box) {
|
|||
}
|
||||
listBox.SetSelectionMode(gtk.SELECTION_BROWSE)
|
||||
listBox.SetHExpand(false)
|
||||
listBox.SetFocusOnClick(false)
|
||||
|
||||
_, err = listBox.Connect("button-press-event", func(listBox *gtkfork.ListBox, ev *gdk.Event) {
|
||||
_, err = listBox.Connect("button-press-event", func(listBox *gtk.ListBox, ev *gdk.Event) {
|
||||
mouseEvent := &gdk.EventButton{ev}
|
||||
if mouseEvent.Type() == gdk.EVENT_2BUTTON_PRESS {
|
||||
err := listSelect(inputView)
|
||||
|
@ -77,126 +78,35 @@ func initList(container *gtk.Box) {
|
|||
listScroll.Add(listBox)
|
||||
container.PackEnd(listScroll, true, true, 0)
|
||||
|
||||
if !config.HideAppIcons {
|
||||
s, _ := container.GetScreen()
|
||||
iconTheme, err = gtk.IconThemeGetForScreen(*s)
|
||||
if err != nil {
|
||||
log.Fatal("failed to get icon theme:", err)
|
||||
}
|
||||
}
|
||||
|
||||
lastEntry := len(gmenu.FilteredEntries) - 1
|
||||
|
||||
for i, entry := range gmenu.FilteredEntries {
|
||||
// Capture variables
|
||||
i := i
|
||||
entry := entry
|
||||
|
||||
row, err := gtk.ListBoxRowNew()
|
||||
if err != nil {
|
||||
log.Fatal("failed to create ListBoxRow:", err)
|
||||
}
|
||||
|
||||
row.SetFocusOnClick(false)
|
||||
|
||||
row.SetName("#" + strconv.Itoa(i))
|
||||
|
||||
container := newBox(gtk.ORIENTATION_HORIZONTAL)
|
||||
|
||||
if !config.HideAppIcons {
|
||||
s, _ := container.GetScreen()
|
||||
theme, err := gtk.IconThemeGetForScreen(*s)
|
||||
if err != nil {
|
||||
log.Fatal("failed to get icon theme:", err)
|
||||
}
|
||||
|
||||
var (
|
||||
pbuf *gdk.Pixbuf
|
||||
img *gtk.Image
|
||||
)
|
||||
|
||||
if entry.Entry != nil && entry.Icon != "" {
|
||||
if path.IsAbs(entry.Icon) {
|
||||
pbuf, err = gdk.PixbufNewFromFileAtSize(entry.Icon, iconSize, iconSize)
|
||||
} else {
|
||||
pbuf, err = theme.LoadIcon(entry.Icon, iconSize, gtk.ICON_LOOKUP_USE_BUILTIN)
|
||||
}
|
||||
}
|
||||
if pbuf == nil || err != nil {
|
||||
var icon string
|
||||
if entry.Entry == nil {
|
||||
icon = "utilities-terminal"
|
||||
} else if entry.Type == desktop.Application {
|
||||
icon = "application-x-executable"
|
||||
} else {
|
||||
icon = "text-html"
|
||||
}
|
||||
pbuf, err = theme.LoadIcon(icon, iconSize, gtk.ICON_LOOKUP_USE_BUILTIN)
|
||||
}
|
||||
if err != nil {
|
||||
// Failed to load icon
|
||||
|
||||
img, err = gtk.ImageNew()
|
||||
if err == nil {
|
||||
img.SetSizeRequest(iconSize, iconSize)
|
||||
}
|
||||
} else {
|
||||
if pbuf.GetWidth() != iconSize && pbuf.GetHeight() != iconSize {
|
||||
pbuf, _ = pbuf.ScaleSimple(iconSize, iconSize, gdk.INTERP_BILINEAR)
|
||||
}
|
||||
|
||||
img, err = gtk.ImageNewFromPixbuf(pbuf)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal("failed to create Icon:", err)
|
||||
}
|
||||
|
||||
img.SetMarginStart(iconMarginStart)
|
||||
img.SetMarginTop(iconMargin)
|
||||
img.SetMarginEnd(iconMargin)
|
||||
img.SetMarginBottom(iconMargin)
|
||||
container.PackStart(img, false, false, 0)
|
||||
}
|
||||
|
||||
labelContainer := newBox(gtk.ORIENTATION_VERTICAL)
|
||||
labelContainer.SetMarginStart(labelMarginStart)
|
||||
|
||||
l, err := gtk.LabelNew(fmt.Sprintf("<b>%s</b>", html.EscapeString(entry.Label)))
|
||||
if err != nil {
|
||||
log.Fatal("failed to create Label:", err)
|
||||
}
|
||||
l.SetUseMarkup(true)
|
||||
|
||||
l.SetHAlign(gtk.ALIGN_START)
|
||||
setNoExpand(&l.Widget)
|
||||
l.SetLineWrap(false)
|
||||
l.SetSingleLineMode(true)
|
||||
l.SetEllipsize(pango.ELLIPSIZE_END)
|
||||
|
||||
if !config.HideAppIcons {
|
||||
l.SetMarginTop(labelMarginTop)
|
||||
}
|
||||
|
||||
labelContainer.PackStart(l, false, false, 0)
|
||||
|
||||
if entry.Entry == nil || (entry.Entry != nil && entry.Comment != "") {
|
||||
comment := ""
|
||||
if entry.Entry != nil {
|
||||
comment = entry.Comment
|
||||
}
|
||||
l, err := gtk.LabelNew(comment)
|
||||
if err != nil {
|
||||
log.Fatal("failed to create Label:", err)
|
||||
}
|
||||
|
||||
l.SetHAlign(gtk.ALIGN_START)
|
||||
setNoExpand(&l.Widget)
|
||||
l.SetLineWrap(false)
|
||||
l.SetSingleLineMode(true)
|
||||
l.SetEllipsize(pango.ELLIPSIZE_END)
|
||||
|
||||
if !config.HideAppIcons {
|
||||
l.SetMarginTop(labelMarginTopComment)
|
||||
}
|
||||
|
||||
labelContainer.Add(l)
|
||||
|
||||
if i == lastEntry {
|
||||
execLabel = l
|
||||
}
|
||||
}
|
||||
|
||||
setNoExpand(&labelContainer.Widget)
|
||||
container.Add(labelContainer)
|
||||
|
||||
setNoExpand(&container.Widget)
|
||||
row.Add(container)
|
||||
|
||||
initRow(container, entry, i, lastEntry)
|
||||
|
||||
listBox.Add(row)
|
||||
}
|
||||
|
||||
|
@ -211,9 +121,103 @@ func initList(container *gtk.Box) {
|
|||
log.Fatal("failed to create ListBox:", err)
|
||||
}
|
||||
|
||||
listBox.SelectRow(listBox.GetRowAtIndex(0))
|
||||
gmenu.SetInput("")
|
||||
}
|
||||
|
||||
func initRow(container *gtk.Box, entry *gmenu.ListEntry, i int, lastEntry int) {
|
||||
if !config.HideAppIcons {
|
||||
img, _ := gtk.ImageNew()
|
||||
img.SetSizeRequest(iconSize, iconSize)
|
||||
glib.IdleAdd(func() { loadIconImage(img, entry) })
|
||||
|
||||
container.PackStart(img, false, false, 0)
|
||||
}
|
||||
|
||||
labelContainer := newBox(gtk.ORIENTATION_VERTICAL)
|
||||
labelContainer.SetMarginStart(labelMarginStart)
|
||||
|
||||
l, err := gtk.LabelNew(fmt.Sprintf("<b>%s</b>", html.EscapeString(entry.Label)))
|
||||
if err != nil {
|
||||
log.Fatal("failed to create Label:", err)
|
||||
}
|
||||
l.SetUseMarkup(true)
|
||||
|
||||
l.SetHAlign(gtk.ALIGN_START)
|
||||
setNoExpand(&l.Widget)
|
||||
l.SetLineWrap(false)
|
||||
l.SetSingleLineMode(true)
|
||||
l.SetEllipsize(pango.ELLIPSIZE_END)
|
||||
|
||||
if !config.HideAppIcons && !config.HideAppDetails {
|
||||
l.SetMarginTop(labelMarginTop)
|
||||
}
|
||||
|
||||
if !config.HideAppDetails {
|
||||
labelContainer.PackStart(l, false, false, 0)
|
||||
} else {
|
||||
labelContainer.PackStart(l, true, true, 0)
|
||||
}
|
||||
|
||||
if config.HideAppDetails {
|
||||
if i == lastEntry {
|
||||
execLabel = l
|
||||
}
|
||||
} else if entry.Entry == nil || (entry.Entry != nil && entry.Comment != "") {
|
||||
comment := ""
|
||||
if entry.Entry != nil {
|
||||
comment = entry.Comment
|
||||
}
|
||||
l, err := gtk.LabelNew(comment)
|
||||
if err != nil {
|
||||
log.Fatal("failed to create Label:", err)
|
||||
}
|
||||
|
||||
l.SetHAlign(gtk.ALIGN_START)
|
||||
setNoExpand(&l.Widget)
|
||||
l.SetLineWrap(false)
|
||||
l.SetSingleLineMode(true)
|
||||
l.SetEllipsize(pango.ELLIPSIZE_END)
|
||||
|
||||
if !config.HideAppIcons {
|
||||
l.SetMarginTop(labelMarginTopComment)
|
||||
}
|
||||
|
||||
labelContainer.Add(l)
|
||||
|
||||
if i == lastEntry {
|
||||
execLabel = l
|
||||
}
|
||||
}
|
||||
|
||||
setNoExpand(&labelContainer.Widget)
|
||||
container.Add(labelContainer)
|
||||
|
||||
setNoExpand(&container.Widget)
|
||||
}
|
||||
|
||||
func loadIconImage(img *gtk.Image, entry *gmenu.ListEntry) {
|
||||
var (
|
||||
pbuf *gdk.Pixbuf
|
||||
err error
|
||||
)
|
||||
|
||||
if entry.Entry != nil && entry.Icon != "" {
|
||||
pbuf, err = loadIcon(entry.Icon)
|
||||
}
|
||||
if pbuf == nil || err != nil {
|
||||
pbuf, err = loadIcon(fallbackIcon(entry))
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal("failed to create Icon:", err)
|
||||
}
|
||||
img.SetFromPixbuf(pbuf)
|
||||
|
||||
img.SetMarginStart(iconMarginStart)
|
||||
img.SetMarginTop(iconMargin)
|
||||
img.SetMarginEnd(iconMargin)
|
||||
img.SetMarginBottom(iconMargin)
|
||||
}
|
||||
func updateList(input string) {
|
||||
listBox.InvalidateSort()
|
||||
|
||||
|
@ -350,3 +354,13 @@ func rowID(row *gtk.ListBoxRow) int {
|
|||
|
||||
return id
|
||||
}
|
||||
|
||||
func fallbackIcon(entry *gmenu.ListEntry) string {
|
||||
if entry.Entry == nil {
|
||||
return "utilities-terminal"
|
||||
} else if entry.Type == desktop.Application {
|
||||
return "application-x-executable"
|
||||
}
|
||||
|
||||
return "text-html"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/gotk3/gotk3/gdk"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
const CachedIconCompressionLevel = 3
|
||||
|
||||
var (
|
||||
iconTheme *gtk.IconTheme
|
||||
iconCacheDir string
|
||||
)
|
||||
|
||||
func loadIcon(icon string) (*gdk.Pixbuf, error) {
|
||||
cachedIcon := path.Join(iconCacheDir, fmt.Sprintf("%x.png", md5.Sum([]byte(icon))))
|
||||
|
||||
if _, err := os.Stat(cachedIcon); !os.IsNotExist(err) {
|
||||
return gdk.PixbufNewFromFileAtSize(cachedIcon, iconSize, iconSize)
|
||||
}
|
||||
|
||||
var (
|
||||
pbuf *gdk.Pixbuf
|
||||
err error
|
||||
)
|
||||
if path.IsAbs(icon) {
|
||||
pbuf, err = gdk.PixbufNewFromFileAtSize(icon, iconSize, iconSize)
|
||||
} else {
|
||||
pbuf, err = iconTheme.LoadIcon(icon, iconSize, gtk.ICON_LOOKUP_USE_BUILTIN)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pbuf.GetWidth() != iconSize || pbuf.GetHeight() != iconSize {
|
||||
pbuf, _ = pbuf.ScaleSimple(iconSize, iconSize, gdk.INTERP_BILINEAR)
|
||||
}
|
||||
|
||||
go cacheIcon(cachedIcon, pbuf)
|
||||
|
||||
return pbuf, nil
|
||||
}
|
||||
|
||||
func cacheIcon(cachedIcon string, pbuf *gdk.Pixbuf) {
|
||||
f, err := os.OpenFile(cachedIcon, os.O_CREATE|os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
pbuf.SavePNG(f.Name(), CachedIconCompressionLevel)
|
||||
}
|
|
@ -4,11 +4,12 @@ import (
|
|||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"git.sr.ht/~tslocum/gmenu/pkg/gmenu"
|
||||
"github.com/gotk3/gotk3/gdk"
|
||||
"github.com/gotk3/gotk3/glib"
|
||||
"github.com/tslocum/gotk3/gdk"
|
||||
"github.com/tslocum/gotk3/gtk"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -20,6 +21,7 @@ type Config struct {
|
|||
|
||||
Width, Height int
|
||||
Resizable bool
|
||||
Fullscreen bool
|
||||
|
||||
HideAppIcons bool
|
||||
}
|
||||
|
@ -28,23 +30,29 @@ var (
|
|||
config = &Config{}
|
||||
listBox *gtk.ListBox
|
||||
inputView *gtk.TextView
|
||||
|
||||
loaded = make(chan bool)
|
||||
)
|
||||
|
||||
func init() {
|
||||
gmenu.SharedInit(&config.Config)
|
||||
|
||||
flag.IntVar(&config.Width, "width", 800, "window width")
|
||||
flag.IntVar(&config.Width, "width", 600, "window width")
|
||||
flag.IntVar(&config.Height, "height", 200, "window height")
|
||||
flag.BoolVar(&config.Resizable, "resizable", false, "allow window to be resized")
|
||||
flag.BoolVar(&config.Fullscreen, "fullscreen", false, "start fullscreen")
|
||||
flag.BoolVar(&config.HideAppIcons, "no-icons", false, "hide application icons")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
go load()
|
||||
|
||||
application, err := gtk.ApplicationNew(appID, glib.APPLICATION_HANDLES_COMMAND_LINE)
|
||||
if err != nil {
|
||||
log.Fatal("failed to create application:", err)
|
||||
}
|
||||
flag.Parse()
|
||||
|
||||
_, err = application.Connect("command-line", func() {
|
||||
flag.Parse()
|
||||
|
@ -64,6 +72,23 @@ func main() {
|
|||
os.Exit(application.Run(os.Args))
|
||||
}
|
||||
|
||||
func load() {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
iconCacheDir = path.Join(homeDir, ".cache", "gmenu", "icons")
|
||||
if _, err := os.Stat(iconCacheDir); os.IsNotExist(err) {
|
||||
os.MkdirAll(iconCacheDir, 0744) // TODO: Warn and disable cache on error
|
||||
}
|
||||
|
||||
gmenu.LoadEntries(&config.Config)
|
||||
gmenu.FilterEntries()
|
||||
|
||||
loaded <- true
|
||||
}
|
||||
|
||||
func onActivate(application *gtk.Application) {
|
||||
w, err := gtk.ApplicationWindowNew(application)
|
||||
|
||||
|
@ -78,8 +103,21 @@ func onActivate(application *gtk.Application) {
|
|||
}
|
||||
w.SetTitle("gmenu")
|
||||
|
||||
gmenu.LoadEntries(&config.Config)
|
||||
gmenu.FilterEntries()
|
||||
w.SetDecorated(false)
|
||||
w.SetBorderWidth(0)
|
||||
w.Stick()
|
||||
w.SetKeepAbove(true)
|
||||
w.SetTypeHint(gdk.WINDOW_TYPE_HINT_UTILITY)
|
||||
|
||||
if !config.Fullscreen {
|
||||
w.SetResizable(config.Resizable)
|
||||
w.SetSizeRequest(config.Width, config.Height)
|
||||
w.SetPosition(gtk.WIN_POS_CENTER)
|
||||
} else {
|
||||
w.Fullscreen()
|
||||
}
|
||||
|
||||
<-loaded
|
||||
|
||||
go gmenu.HandleInput(func(input string) {
|
||||
_, err := glib.IdleAdd(updateList, input)
|
||||
|
@ -93,19 +131,11 @@ func onActivate(application *gtk.Application) {
|
|||
gmenu.FilteredEntries = append(gmenu.FilteredEntries, &gmenu.ListEntry{Label: "Shell command", Entry: nil})
|
||||
|
||||
container := newBox(gtk.ORIENTATION_VERTICAL)
|
||||
|
||||
initList(container)
|
||||
|
||||
w.Add(container)
|
||||
|
||||
w.SetResizable(config.Resizable)
|
||||
w.SetSizeRequest(config.Width, config.Height)
|
||||
w.SetPosition(gtk.WIN_POS_CENTER)
|
||||
|
||||
w.SetDecorated(false)
|
||||
w.SetBorderWidth(0)
|
||||
w.Stick()
|
||||
w.SetKeepAbove(true)
|
||||
|
||||
_, err = w.Connect("key-press-event", func(win *gtk.ApplicationWindow, ev *gdk.Event) bool {
|
||||
keyEvent := &gdk.EventKey{ev}
|
||||
switch keyEvent.KeyVal() {
|
||||
|
|
8
go.mod
8
go.mod
|
@ -4,14 +4,12 @@ go 1.12
|
|||
|
||||
require (
|
||||
git.sr.ht/~tslocum/desktop v0.1.1
|
||||
github.com/gotk3/gotk3 v0.0.0-20190620081259-6dcdf9e5c51e
|
||||
github.com/gotk3/gotk3 v0.0.0-20190809225113-dc58eba1cccc
|
||||
github.com/jroimartin/gocui v0.4.0
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/lithammer/fuzzysearch v1.0.2
|
||||
github.com/mattn/go-isatty v0.0.8
|
||||
github.com/mattn/go-isatty v0.0.9
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/nsf/termbox-go v0.0.0-20190624072549-eeb6cd0a1762 // indirect
|
||||
github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/tslocum/gotk3 v0.0.0-20190727120037-6cb68ea19890
|
||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect
|
||||
)
|
||||
|
|
20
go.sum
20
go.sum
|
@ -1,24 +1,20 @@
|
|||
git.sr.ht/~tslocum/desktop v0.1.1 h1:hS1DgT1Ur0DR42Z4vr+Zsasjjd8M9PVwIEmeAd1xLS4=
|
||||
git.sr.ht/~tslocum/desktop v0.1.1/go.mod h1:cUn0Q8ALjkAq40qSei795yN3CfO5pkeYKo2gmzaZ2SI=
|
||||
github.com/gotk3/gotk3 v0.0.0-20190620081259-6dcdf9e5c51e h1:KFy3swDjmbaSAE6b1iExIgsYt0OkfoLP3HjLm4ifSR8=
|
||||
github.com/gotk3/gotk3 v0.0.0-20190620081259-6dcdf9e5c51e/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo=
|
||||
github.com/gotk3/gotk3 v0.0.0-20190809225113-dc58eba1cccc h1:QtXtC6AdJ57L/rw/YMF41a+6YmLTy92IvxsCjDp4dYE=
|
||||
github.com/gotk3/gotk3 v0.0.0-20190809225113-dc58eba1cccc/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo=
|
||||
github.com/jroimartin/gocui v0.4.0 h1:52jnalstgmc25FmtGcWqa0tcbMEWS6RpFLsOIO+I+E8=
|
||||
github.com/jroimartin/gocui v0.4.0/go.mod h1:7i7bbj99OgFHzo7kB2zPb8pXLqMBSQegY7azfqXMkyY=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/lithammer/fuzzysearch v1.0.2 h1:AjCE2iwc5y+8K+h2nXVc0Pmrpjvu+JVqMgiZ0oakXDM=
|
||||
github.com/lithammer/fuzzysearch v1.0.2/go.mod h1:bvAJyokfCQ7Vknrd4Kgc+izmMrPj5CiBAu2t6rK1Kak=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/nsf/termbox-go v0.0.0-20190624072549-eeb6cd0a1762 h1:44Lv0bNi88GweB54TCjB/lEJgp+2Ze5WFpwNu0nh0ag=
|
||||
github.com/nsf/termbox-go v0.0.0-20190624072549-eeb6cd0a1762/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317 h1:hhGN4SFXgXo61Q4Sjj/X9sBjyeSa2kdpaOzCO+8EVQw=
|
||||
github.com/nsf/termbox-go v0.0.0-20190817171036-93860e161317/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/tslocum/gotk3 v0.0.0-20190727120037-6cb68ea19890 h1:E4ShJr9mkfrOgv2gJfLhuc8s1uFfWsTG24h2JDIjrVs=
|
||||
github.com/tslocum/gotk3 v0.0.0-20190727120037-6cb68ea19890/go.mod h1:lKW1BMxjgJ9vFqOZ2pNvC6p6ln6en3KqvV4KRt5FLB4=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 h1:LepdCS8Gf/MVejFIt8lsiexZATdoGVyp5bcyS+rYoUI=
|
||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
Loading…
Reference in New Issue