resolve conflicts

This commit is contained in:
piotr 2021-09-23 00:25:35 +02:00
parent c974593f77
commit 5fcc6239b6
4 changed files with 132 additions and 54 deletions

Binary file not shown.

127
main.go
View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"path"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
@ -20,16 +21,16 @@ import (
"github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/gtk"
) )
const version = "0.1.12" const version = "0.2.0"
var ( var (
appDirs []string appDirs []string
configDirectory string configDirectory string
pinnedFile string pinnedFile string
pinned []string pinned []string
src glib.SourceHandle //src glib.SourceHandle
id2entry map[string]desktopEntry id2entry map[string]desktopEntry
preferredApps map[string]interface{} preferredApps map[string]interface{}
) )
var categoryNames = [...]string{ var categoryNames = [...]string{
@ -82,6 +83,7 @@ var desktopEntries []desktopEntry
// UI elements // UI elements
var ( var (
win *gtk.Window
resultWindow *gtk.ScrolledWindow resultWindow *gtk.ScrolledWindow
fileSearchResults []string fileSearchResults []string
searchEntry *gtk.SearchEntry searchEntry *gtk.SearchEntry
@ -98,6 +100,7 @@ var (
statusLabel *gtk.Label statusLabel *gtk.Label
status string status string
ignore string ignore string
showWindowTrigger bool
) )
func defaultStringIfBlank(s, fallback string) string { func defaultStringIfBlank(s, fallback string) string {
@ -125,45 +128,74 @@ var term = flag.String("term", defaultStringIfBlank(os.Getenv("TERM"), "alacritt
var nameLimit = flag.Int("fslen", 80, "File Search name length Limit") var nameLimit = flag.Int("fslen", 80, "File Search name length Limit")
var noCats = flag.Bool("nocats", false, "Disable filtering by category") var noCats = flag.Bool("nocats", false, "Disable filtering by category")
var noFS = flag.Bool("nofs", false, "Disable file search") var noFS = flag.Bool("nofs", false, "Disable file search")
var resident = flag.Bool("r", false, "Leave the program resident in memory")
var debug = flag.Bool("d", false, "Turn on debug messages")
func main() { func main() {
timeStart := time.Now() timeStart := time.Now()
flag.Parse() flag.Parse()
if *debug {
log.SetLevel(log.DebugLevel)
}
if *displayVersion { if *displayVersion {
fmt.Printf("nwg-drawer version %s\n", version) fmt.Printf("nwg-drawer version %s\n", version)
os.Exit(0) os.Exit(0)
} }
// Gentle SIGTERM handler thanks to reiki4040 https://gist.github.com/reiki4040/be3705f307d3cd136e85 // Gentle SIGTERM handler thanks to reiki4040 https://gist.github.com/reiki4040/be3705f307d3cd136e85
// v0.2: we also need to support SIGUSR from now on
signalChan := make(chan os.Signal, 1) signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGTERM) signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGUSR1)
go func() { go func() {
for { for {
s := <-signalChan s := <-signalChan
if s == syscall.SIGTERM { switch s {
log.Info("SIGTERM received, bye bye!") case syscall.SIGTERM:
log.Debug("SIGTERM received, bye bye")
gtk.MainQuit() gtk.MainQuit()
case syscall.SIGUSR1:
if *resident {
// As win.Show() called from inside a goroutine randomly crashes GTK,
// let's just set e helper variable here. We'll be checking it with glib.TimeoutAdd.
log.Debug("SIGUSR1 received, showing the window")
showWindowTrigger = true
} else {
log.Debug("SIGUSR1 received, and I'm not resident, bye bye")
gtk.MainQuit()
}
default:
log.Info("Unknown signal")
} }
} }
}() }()
// We want the same key/mouse binding to turn the dock off: kill the running instance and exit. // If running instance found and running residently, we want it to refresh and show the window.
lockFilePath := fmt.Sprintf("%s/nwg-drawer.lock", tempDir()) // Otherwise we want the same command to terminate the drawer: kill the running instance and exit.
//lockFilePath := fmt.Sprintf("%s/nwg-drawer.lock", tempDir())
lockFilePath := path.Join(tempDir(), "nwg-drawer.lock")
lockFile, err := singleinstance.CreateLockFile(lockFilePath) lockFile, err := singleinstance.CreateLockFile(lockFilePath)
if err != nil { if err != nil {
pid, err := readTextFile(lockFilePath) pid, err := readTextFile(lockFilePath)
if err == nil { if err == nil {
i, err := strconv.Atoi(pid) i, err := strconv.Atoi(pid)
if err == nil { if err == nil {
log.Info("Running instance found, sending SIGTERM and exiting...") if *resident {
syscall.Kill(i, syscall.SIGTERM) log.Warnf("Resident instance already running (PID %v)", i)
} else {
log.Infof("Showing resident instance (PID %v)", i)
syscall.Kill(i, syscall.SIGUSR1)
}
} }
} }
os.Exit(0) os.Exit(0)
} }
defer lockFile.Close() defer lockFile.Close()
log.Infof("term: %s", *term)
// LANGUAGE // LANGUAGE
if *lang == "" && os.Getenv("LANG") != "" { if *lang == "" && os.Getenv("LANG") != "" {
*lang = strings.Split(os.Getenv("LANG"), ".")[0] *lang = strings.Split(os.Getenv("LANG"), ".")[0]
@ -226,7 +258,7 @@ func main() {
gtk.AddProviderForScreen(screen, cssProvider, gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) gtk.AddProviderForScreen(screen, cssProvider, gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
} }
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) win, err = gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
if err != nil { if err != nil {
log.Fatal("Unable to create window:", err) log.Fatal("Unable to create window:", err)
} }
@ -275,7 +307,11 @@ func main() {
searchEntry.GrabFocus() searchEntry.GrabFocus()
searchEntry.SetText("") searchEntry.SetText("")
} else { } else {
gtk.MainQuit() if !*resident {
gtk.MainQuit()
} else {
restoreStateAndHide()
}
} }
return false return false
case gdk.KEY_downarrow, gdk.KEY_Up, gdk.KEY_Down, gdk.KEY_Left, gdk.KEY_Right, gdk.KEY_Tab, case gdk.KEY_downarrow, gdk.KEY_Up, gdk.KEY_Down, gdk.KEY_Left, gdk.KEY_Right, gdk.KEY_Tab,
@ -290,18 +326,6 @@ func main() {
} }
}) })
// Close the window on leave, but not immediately, to avoid accidental closes
win.Connect("leave-notify-event", func() {
src = glib.TimeoutAdd(uint(500), func() bool {
gtk.MainQuit()
return false
})
})
win.Connect("enter-notify-event", func() {
cancelClose()
})
/* /*
In case someone REALLY needed to use X11 - for some stupid Zoom meeting or something, this allows In case someone REALLY needed to use X11 - for some stupid Zoom meeting or something, this allows
the drawer to behave properly on Openbox, and possibly somewhere else. For sure not on i3. the drawer to behave properly on Openbox, and possibly somewhere else. For sure not on i3.
@ -341,13 +365,17 @@ func main() {
resultWindow, _ = gtk.ScrolledWindowNew(nil, nil) resultWindow, _ = gtk.ScrolledWindowNew(nil, nil)
resultWindow.SetEvents(int(gdk.ALL_EVENTS_MASK)) resultWindow.SetEvents(int(gdk.ALL_EVENTS_MASK))
resultWindow.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) resultWindow.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
resultWindow.Connect("enter-notify-event", func() { /*resultWindow.Connect("enter-notify-event", func() {
cancelClose() cancelClose()
}) })*/
resultWindow.Connect("button-release-event", func(sw *gtk.ScrolledWindow, e *gdk.Event) bool { resultWindow.Connect("button-release-event", func(sw *gtk.ScrolledWindow, e *gdk.Event) bool {
btnEvent := gdk.EventButtonNewFromEvent(e) btnEvent := gdk.EventButtonNewFromEvent(e)
if btnEvent.Button() == 1 || btnEvent.Button() == 3 { if btnEvent.Button() == 1 || btnEvent.Button() == 3 {
gtk.MainQuit() if !*resident {
gtk.MainQuit()
} else {
restoreStateAndHide()
}
return true return true
} }
return false return false
@ -392,6 +420,7 @@ func main() {
statusLineWrapper.PackStart(statusLabel, true, false, 0) statusLineWrapper.PackStart(statusLabel, true, false, 0)
win.ShowAll() win.ShowAll()
if !*noFS { if !*noFS {
fileSearchResultWrapper.SetSizeRequest(appFlowBox.GetAllocatedWidth(), 1) fileSearchResultWrapper.SetSizeRequest(appFlowBox.GetAllocatedWidth(), 1)
fileSearchResultWrapper.Hide() fileSearchResultWrapper.Hide()
@ -399,8 +428,50 @@ func main() {
if !*noCats { if !*noCats {
categoriesWrapper.SetSizeRequest(1, categoriesWrapper.GetAllocatedHeight()*2) categoriesWrapper.SetSizeRequest(1, categoriesWrapper.GetAllocatedHeight()*2)
} }
if *resident {
win.Hide()
}
t := time.Now() t := time.Now()
log.Info(fmt.Sprintf("UI created in %v ms. Thank you for your patience.", t.Sub(timeStart).Milliseconds())) log.Info(fmt.Sprintf("UI created in %v ms. Thank you for your patience.", t.Sub(timeStart).Milliseconds()))
// Check if showing the window has been requested (SIGUSR1)
glib.TimeoutAdd(uint(1), func() bool {
if showWindowTrigger && win != nil && !win.IsVisible() {
win.ShowAll()
// focus 1st element
b := appFlowBox.GetChildAtIndex(0)
if b != nil {
button, err := b.GetChild()
if err == nil {
button.ToWidget().GrabFocus()
}
}
}
showWindowTrigger = false
return true
})
gtk.Main() gtk.Main()
} }
func restoreStateAndHide() {
timeStart1 := time.Now()
win.Hide()
// 1. clear search
searchEntry.SetText("")
// 2. clear category filter (in gotk3 it means: rebuild, as we have no filtering here)
appFlowBox = setUpAppsFlowBox(nil, "")
for _, btn := range catButtons {
btn.SetImagePosition(gtk.POS_LEFT)
btn.SetSizeRequest(0, 0)
}
// 3. scroll to the top
resultWindow.GetVAdjustment().SetValue(0)
t := time.Now()
log.Debugf(fmt.Sprintf("UI hidden and restored in the backgroud in %v ms", t.Sub(timeStart1).Milliseconds()))
}

View File

@ -19,7 +19,6 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/gotk3/gotk3/gdk" "github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/gtk"
"github.com/joshuarubin/go-sway" "github.com/joshuarubin/go-sway"
) )
@ -34,12 +33,12 @@ We might have left the window by accident, so let's clear the timeout if window
Furthermore - hovering a widget triggers window leave-notify-event event, and the timeout Furthermore - hovering a widget triggers window leave-notify-event event, and the timeout
needs to be cleared as well. needs to be cleared as well.
*/ */
func cancelClose() { /*func cancelClose() {
if src > 0 { if src > 0 {
glib.SourceRemove(src) glib.SourceRemove(src)
src = 0 src = 0
} }
} }*/
func createPixbuf(icon string, size int) (*gdk.Pixbuf, error) { func createPixbuf(icon string, size int) (*gdk.Pixbuf, error) {
iconTheme, err := gtk.IconThemeGetDefault() iconTheme, err := gtk.IconThemeGetDefault()
@ -563,12 +562,20 @@ func launch(command string, terminal bool) {
msg := fmt.Sprintf("env vars: %s; command: '%s'; args: %s\n", envVars, elements[cmdIdx], elements[1+cmdIdx:]) msg := fmt.Sprintf("env vars: %s; command: '%s'; args: %s\n", envVars, elements[cmdIdx], elements[1+cmdIdx:])
log.Info(msg) log.Info(msg)
go cmd.Run() cmd.Start()
if *resident {
restoreStateAndHide()
} else {
gtk.MainQuit()
}
/*go cmd.Run()
glib.TimeoutAdd(uint(150), func() bool { glib.TimeoutAdd(uint(150), func() bool {
gtk.MainQuit() gtk.MainQuit()
return false return false
}) })*/
} }
func open(filePath string, xdgOpen bool) { func open(filePath string, xdgOpen bool) {
@ -586,10 +593,15 @@ func open(filePath string, xdgOpen bool) {
} else { } else {
cmd = exec.Command(*fileManager, filePath) cmd = exec.Command(*fileManager, filePath)
} }
fmt.Printf("Executing: %s", cmd) log.Infof("Executing: %s", cmd)
cmd.Start() cmd.Start()
gtk.MainQuit() if *resident {
restoreStateAndHide()
} else {
gtk.MainQuit()
}
} }
// Returns map output name -> gdk.Monitor // Returns map output name -> gdk.Monitor

View File

@ -7,6 +7,7 @@ import (
"strings" "strings"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/gotk3/gotk3/gdk" "github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/gtk"
) )
@ -34,19 +35,13 @@ func setUpPinnedFlowBox() *gtk.FlowBox {
btn, _ := gtk.ButtonNew() btn, _ := gtk.ButtonNew()
var pixbuf *gdk.Pixbuf
var img *gtk.Image var img *gtk.Image
var err error
if entry.Icon != "" { if entry.Icon != "" {
pixbuf, err = createPixbuf(entry.Icon, *iconSize) pixbuf, _ := createPixbuf(entry.Icon, *iconSize)
img, _ = gtk.ImageNewFromPixbuf(pixbuf)
} else { } else {
pixbuf, err = createPixbuf("image-missing", *iconSize) img, _ = gtk.ImageNewFromIconName("image-missing", gtk.ICON_SIZE_INVALID)
} }
if err != nil {
log.Error(err)
pixbuf, _ = createPixbuf("unknown", *iconSize)
}
img, _ = gtk.ImageNewFromPixbuf(pixbuf)
btn.SetImage(img) btn.SetImage(img)
btn.SetAlwaysShowImage(true) btn.SetAlwaysShowImage(true)
@ -92,11 +87,11 @@ func setUpPinnedFlowBox() *gtk.FlowBox {
item.(*gtk.Widget).SetCanFocus(false) item.(*gtk.Widget).SetCanFocus(false)
}) })
} }
flowBox.Connect("enter-notify-event", func() { /*flowBox.Connect("enter-notify-event", func() {
cancelClose() cancelClose()
}) })*/
flowBox.ShowAll() //flowBox.ShowAll()
return flowBox return flowBox
} }
@ -115,9 +110,9 @@ func setUpCategoriesButtonBox() *gtk.EventBox {
} }
eventBox, _ := gtk.EventBoxNew() eventBox, _ := gtk.EventBoxNew()
eventBox.Connect("enter-notify-event", func() { /*eventBox.Connect("enter-notify-event", func() {
cancelClose() cancelClose()
}) })*/
hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) hBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
eventBox.Add(hBox) eventBox.Add(hBox)
button, _ := gtk.ButtonNewWithLabel("All") button, _ := gtk.ButtonNewWithLabel("All")
@ -246,6 +241,7 @@ func flowBoxButton(entry desktopEntry) *gtk.Button {
if entry.Icon != "" { if entry.Icon != "" {
pixbuf, err = createPixbuf(entry.Icon, *iconSize) pixbuf, err = createPixbuf(entry.Icon, *iconSize)
} else { } else {
log.Warnf("Undefined icon for %s", entry.Name)
pixbuf, err = createPixbuf("image-missing", *iconSize) pixbuf, err = createPixbuf("image-missing", *iconSize)
} }
if err != nil { if err != nil {
@ -295,9 +291,9 @@ func setUpFileSearchResultContainer() *gtk.FlowBox {
} }
flowBox, _ := gtk.FlowBoxNew() flowBox, _ := gtk.FlowBoxNew()
flowBox.SetProperty("orientation", gtk.ORIENTATION_VERTICAL) flowBox.SetProperty("orientation", gtk.ORIENTATION_VERTICAL)
flowBox.Connect("enter-notify-event", func() { /*flowBox.Connect("enter-notify-event", func() {
cancelClose() cancelClose()
}) })*/
fileSearchResultWrapper.PackStart(flowBox, false, false, 10) fileSearchResultWrapper.PackStart(flowBox, false, false, 10)
return flowBox return flowBox
@ -323,9 +319,9 @@ func walk(path string, d fs.DirEntry, e error) error {
func setUpSearchEntry() *gtk.SearchEntry { func setUpSearchEntry() *gtk.SearchEntry {
searchEntry, _ := gtk.SearchEntryNew() searchEntry, _ := gtk.SearchEntryNew()
searchEntry.SetPlaceholderText("Type to search") searchEntry.SetPlaceholderText("Type to search")
searchEntry.Connect("enter-notify-event", func() { /*searchEntry.Connect("enter-notify-event", func() {
cancelClose() cancelClose()
}) })*/
searchEntry.Connect("search-changed", func() { searchEntry.Connect("search-changed", func() {
for _, btn := range catButtons { for _, btn := range catButtons {
btn.SetImagePosition(gtk.POS_LEFT) btn.SetImagePosition(gtk.POS_LEFT)
@ -380,7 +376,6 @@ func setUpSearchEntry() *gtk.SearchEntry {
if w == nil && fileSearchResultFlowBox != nil { if w == nil && fileSearchResultFlowBox != nil {
f := fileSearchResultFlowBox.GetChildAtIndex(0) f := fileSearchResultFlowBox.GetChildAtIndex(0)
if f != nil { if f != nil {
//f.SetCanFocus(false)
button, err := f.GetChild() button, err := f.GetChild()
if err == nil { if err == nil {
button.ToWidget().SetCanFocus(true) button.ToWidget().SetCanFocus(true)