diff --git a/Makefile b/Makefile index 14ae57e..3f72f2e 100644 --- a/Makefile +++ b/Makefile @@ -16,11 +16,12 @@ install: sleep 1 mkdir -p /usr/share/nwg-drawer cp -r desktop-directories /usr/share/nwg-drawer + cp -r img /usr/share/nwg-drawer cp drawer.css /usr/share/nwg-drawer cp bin/nwg-drawer /usr/bin - cp LICENSE /usr/share/licenses/nwg-shell-drawer/LICENSE - cp README.md /usr/share/doc/nwg-shell-drawer/README.md + install -Dm 644 -t "/usr/share/licenses/nwg-drawer" LICENSE + install -Dm 644 -t "/usr/share/doc/nwg-drawer" README.md uninstall: rm -r /usr/share/nwg-drawer diff --git a/go.mod b/go.mod index 7e9d8b3..777d174 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,6 @@ require ( require ( github.com/joshuarubin/lifecycle v1.1.4 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect ) diff --git a/go.sum b/go.sum index bc2aaf4..cc896ad 100644 --- a/go.sum +++ b/go.sum @@ -36,12 +36,16 @@ golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/img/exit.svg b/img/exit.svg new file mode 100644 index 0000000..7a36f22 --- /dev/null +++ b/img/exit.svg @@ -0,0 +1,64 @@ + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/img/lock.svg b/img/lock.svg new file mode 100644 index 0000000..47b5caf --- /dev/null +++ b/img/lock.svg @@ -0,0 +1,66 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/img/poweroff.svg b/img/poweroff.svg new file mode 100644 index 0000000..14cef92 --- /dev/null +++ b/img/poweroff.svg @@ -0,0 +1,52 @@ + + + + + + + + image/svg+xml + + + + + + diff --git a/img/reboot.svg b/img/reboot.svg new file mode 100644 index 0000000..265a119 --- /dev/null +++ b/img/reboot.svg @@ -0,0 +1,59 @@ + + + + + + + + image/svg+xml + + + + + + + + diff --git a/img/sleep.svg b/img/sleep.svg new file mode 100644 index 0000000..2110cb5 --- /dev/null +++ b/img/sleep.svg @@ -0,0 +1,52 @@ + + + + + + + + image/svg+xml + + + + + + diff --git a/main.go b/main.go index 31fd0e7..6c2fa55 100644 --- a/main.go +++ b/main.go @@ -171,6 +171,12 @@ var nameLimit = flag.Int("fslen", 80, "File Search name LENgth Limit") var noCats = flag.Bool("nocats", false, "Disable filtering by category") var noFS = flag.Bool("nofs", false, "Disable file search") var resident = flag.Bool("r", false, "Leave the program resident in memory") +var pbExit = flag.String("pbexit", "", "command for the Exit power bar icon") +var pbLock = flag.String("pblock", "", "command for the Lock power bar icon") +var pbPoweroff = flag.String("pbpoweroff", "", "command for the Poweroff power bar icon") +var pbReboot = flag.String("pbreboot", "", "command for the Reboot power bar icon") +var pbSleep = flag.String("pbsleep", "", "command for the sleep power bar icon") +var pbSize = flag.Int("pbsize", 64, "power bar icon size") var debug = flag.Bool("d", false, "Turn on Debug messages") func main() { @@ -559,6 +565,35 @@ func main() { resultsWrapper.PackEnd(wrapper, false, false, 10) } + // Power Button Bar + if *pbExit != "" || *pbLock != "" || *pbPoweroff != "" || *pbReboot != "" || *pbSleep != "" { + powerBarWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + outerVBox.PackStart(powerBarWrapper, false, false, 0) + powerButtonsWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + powerBarWrapper.PackStart(powerButtonsWrapper, true, false, 12) + + if *pbLock != "" { + btn := powerButton("/usr/share/nwg-drawer/img/lock.svg", *pbLock) + powerButtonsWrapper.PackStart(btn, true, false, 0) + } + if *pbExit != "" { + btn := powerButton("/usr/share/nwg-drawer/img/exit.svg", *pbExit) + powerButtonsWrapper.PackStart(btn, true, false, 0) + } + if *pbReboot != "" { + btn := powerButton("/usr/share/nwg-drawer/img/reboot.svg", *pbReboot) + powerButtonsWrapper.PackStart(btn, true, false, 0) + } + if *pbSleep != "" { + btn := powerButton("/usr/share/nwg-drawer/img/sleep.svg", *pbSleep) + powerButtonsWrapper.PackStart(btn, true, false, 0) + } + if *pbPoweroff != "" { + btn := powerButton("/usr/share/nwg-drawer/img/poweroff.svg", *pbPoweroff) + powerButtonsWrapper.PackStart(btn, true, false, 0) + } + } + statusLineWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) statusLineWrapper.SetProperty("name", "status-line-wrapper") outerVBox.PackStart(statusLineWrapper, false, false, 10) diff --git a/tools.go b/tools.go index 4d0e16c..98c71b7 100644 --- a/tools.go +++ b/tools.go @@ -78,7 +78,7 @@ func mapXdgUserDirs() map[string]string { result["pictures"] = filepath.Join(home, "Pictures") result["videos"] = filepath.Join(home, "Videos") - userDirsFile := filepath.Join(filepath.Join(os.Getenv("XDG_CONFIG_HOME"), "user-dirs.dirs")) + userDirsFile := filepath.Join(filepath.Join(configHome(), "user-dirs.dirs")) if pathExists(userDirsFile) { log.Debugf("userDirsFile found: %s", userDirsFile) log.Info(fmt.Sprintf("Using XDG user dirs from %s", userDirsFile)) @@ -166,6 +166,13 @@ func configDir() string { return dir } +func configHome() string { + if os.Getenv("XDG_CONFIG_HOME") != "" { + return os.Getenv("XDG_CONFIG_HOME") + } + return path.Join(os.Getenv("HOME"), ".config") +} + func dataDir() string { var dir string if xdgData := os.Getenv("XDG_DATA_HOME"); xdgData != "" { diff --git a/uicomponents.go b/uicomponents.go index 9000c38..6997570 100644 --- a/uicomponents.go +++ b/uicomponents.go @@ -281,12 +281,54 @@ func flowBoxButton(entry desktopEntry) *gtk.Button { button.Connect("enter-notify-event", func() { statusLabel.SetText(desc) }) + button.Connect("leave-notify-event", func() { + statusLabel.SetText("") + }) button.Connect("focus-in-event", func() { statusLabel.SetText(desc) }) return button } +func powerButton(iconPath, command string) *gtk.Button { + button, _ := gtk.ButtonNew() + button.SetAlwaysShowImage(true) + + var pixbuf *gdk.Pixbuf + var img *gtk.Image + var err error + pixbuf, err = gdk.PixbufNewFromFileAtSize(iconPath, *pbSize, *pbSize) + if err != nil { + pixbuf, _ = createPixbuf("unknown", *pbSize) + log.Warnf("Couldn't find icon %s", iconPath) + } + img, _ = gtk.ImageNewFromPixbuf(pixbuf) + button.SetImage(img) + button.SetImagePosition(gtk.POS_TOP) + + button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool { + btnEvent := gdk.EventButtonNewFromEvent(e) + if btnEvent.Button() == 1 { + launch(command, false) + return true + } + return false + }) + button.Connect("activate", func() { + launch(command, false) + }) + button.Connect("enter-notify-event", func() { + statusLabel.SetText(command) + }) + button.Connect("leave-notify-event", func() { + statusLabel.SetText("") + }) + button.Connect("focus-in-event", func() { + statusLabel.SetText(command) + }) + return button +} + func setUpFileSearchResultContainer() *gtk.FlowBox { if fileSearchResultFlowBox != nil { fileSearchResultFlowBox.Destroy()