16 Commits

Author SHA1 Message Date
Piotr Miller
c5e39f179f Merge pull request #18 from nwg-piotr/searchres
focus first search result #17
2021-08-30 03:17:49 +02:00
piotr
ce48848589 focus first search result #17 2021-08-29 03:37:00 +02:00
Piotr Miller
9d0c4d2e5f Merge pull request #16 from nwg-piotr/fixnofs
fix crash on a category button click while file search turned off (`-nofs`)
2021-08-27 01:33:01 +02:00
piotr
a7968d8510 version bump 2021-08-27 01:23:16 +02:00
piotr
e601316480 add missing nil check #15 2021-08-27 01:21:41 +02:00
piotr
4818dc3358 update README 2021-08-21 01:45:22 +02:00
piotr
9afd7dca20 update README 2021-08-21 01:41:45 +02:00
piotr
eb1e9994e7 update README 2021-08-21 01:40:19 +02:00
Piotr Miller
3e2b9395d5 Merge pull request #14 from nwg-piotr/files
xdg-open support + customization + 1 bug fixed
2021-08-21 00:49:24 +02:00
piotr
061d5e1ca9 avoid unwanted closes 2021-08-21 00:34:50 +02:00
piotr
dc50203ee3 update README 2021-08-20 05:43:16 +02:00
piotr
656347855b update README 2021-08-20 05:40:51 +02:00
piotr
81aeb10311 update README 2021-08-20 05:36:27 +02:00
piotr
04a292c2ec check err just in case 2021-08-20 05:02:37 +02:00
piotr
6912e7f320 xdg-open or open in FM 2021-08-20 04:46:26 +02:00
piotr
41d48a0824 version bump 2021-08-17 22:49:09 +02:00
5 changed files with 143 additions and 28 deletions

View File

@@ -25,17 +25,18 @@ and `nwggrid`.
### Dependencies
- go 1.16 (just to build)
- go >=1.16 (just to build)
- gtk3
- gtk-layer-shell
- xdg-utils
Optional (recommended):
- thunar
- alacritty
You may use another file manager and terminal emulator (see command line arguments), but for now the program has
only been tested with the two mentioned above.
You may use another file manager and terminal emulator (see command line arguments), but mentioned above have been
confirmed to work well with the program. Also see **Files** below.
### Steps
@@ -85,6 +86,37 @@ Usage of nwg-drawer:
Edit `~/.config/nwg-panel/drawer.css` to your taste.
## Files
When the search phrase is at least 3 characters long, your XDG user directories are being searched.
![screenshot-03.png](https://scrot.cloud/images/2021/05/30/screenshot-03.png)
Use the **left mouse button** to open a file with the `xdg-open` command. As configuring file associations for it is
PITA, you may override them, by creating the `~/.config/nwg-panel/preferred-apps.json` file with your own definitions.
### Sample file content
```json
{
"\\.pdf$": "atril",
"\\.svg$": "inkscape",
"\\.(jpg|png|tiff|gif)$": "feh",
"\\.(mp3|ogg|flac|wav|wma)$": "audacious",
"\\.(avi|mp4|mkv|mov|wav)$": "mpv",
"\\.(doc|docx|xls|xlsx)$": "libreoffice"
}
```
Use the **right mouse button** to open the file with your file manager (see `-fm` argument). The result depends on the
file manager you use.
- thunar will open the file location
- pcmanfm will open the file with its associated program
- caja won't open anything, except for directories
I've noy yet tried other file managers.
## Credits
This program uses some great libraries:

Binary file not shown.

24
main.go
View File

@@ -19,7 +19,7 @@ import (
"github.com/gotk3/gotk3/gtk"
)
const version = "0.1.5"
const version = "0.1.9"
var (
appDirs []string
@@ -28,6 +28,7 @@ var (
pinned []string
src glib.SourceHandle
id2entry map[string]desktopEntry
preferredApps map[string]interface{}
)
var categoryNames = [...]string{
@@ -188,6 +189,16 @@ func main() {
status = parseDesktopFiles(desktopFiles)
// For opening files we use xdg-open. As its configuration is PITA, we may override some associations
// in the ~/.config/nwg-panel/preferred-apps.json file.
paFile := filepath.Join(configDirectory, "preferred-apps.json")
preferredApps, err = loadPreferredApps(paFile)
if err != nil {
println(fmt.Sprintf("Custom associations file %s not found or invalid", paFile))
} else {
println(fmt.Sprintf("Found %v associations in %s", len(preferredApps), paFile))
}
// USER INTERFACE
gtk.Init(nil)
@@ -243,15 +254,6 @@ func main() {
gtk.MainQuit()
})
win.Connect("button-release-event", func(sw *gtk.Window, e *gdk.Event) bool {
btnEvent := gdk.EventButtonNewFromEvent(e)
if btnEvent.Button() == 1 || btnEvent.Button() == 3 {
gtk.MainQuit()
return true
}
return false
})
win.Connect("key-press-event", func(window *gtk.Window, event *gdk.Event) bool {
key := &gdk.EventKey{Event: event}
switch key.KeyVal() {
@@ -270,7 +272,7 @@ func main() {
default:
if !searchEntry.IsFocus() {
searchEntry.GrabFocus()
searchEntry.GrabFocusWithoutSelecting()
}
return false
}

View File

@@ -2,6 +2,8 @@ package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/fs"
@@ -10,6 +12,7 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"sort"
"strings"
"time"
@@ -243,6 +246,25 @@ func getAppDirs() []string {
return dirs
}
func loadPreferredApps(path string) (map[string]interface{}, error) {
jsonFile, err := os.Open(path)
if err != nil {
return nil, err
}
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var result map[string]interface{}
json.Unmarshal([]byte(byteValue), &result)
if len(result) == 0 {
return nil, errors.New("json invalid or empty")
}
return result, nil
}
func listFiles(dir string) ([]fs.FileInfo, error) {
files, err := ioutil.ReadDir(dir)
if err == nil {
@@ -622,14 +644,25 @@ func launch(command string, terminal bool) {
})
}
func open(filePath string) {
cmd := exec.Command(*fileManager, filePath)
func open(filePath string, xdgOpen bool) {
var cmd *exec.Cmd
if xdgOpen {
cmd = exec.Command("xdg-open", filePath)
// Look for possible custom file association
for key, element := range preferredApps {
r, err := regexp.Compile(key)
if err == nil && r.MatchString(filePath) {
cmd = exec.Command(fmt.Sprintf("%v", element), filePath)
break
}
}
} else {
cmd = exec.Command(*fileManager, filePath)
}
fmt.Printf("Executing: %s", cmd)
cmd.Start()
glib.TimeoutAdd(uint(150), func() bool {
gtk.MainQuit()
return false
})
}
// Returns map output name -> gdk.Monitor

View File

@@ -146,7 +146,9 @@ func setUpCategoriesButtonBox() *gtk.EventBox {
w := b.GetAllocatedWidth()
b.SetImagePosition(gtk.POS_TOP)
b.SetSizeRequest(w, 0)
if fileSearchResultWrapper != nil {
fileSearchResultWrapper.Hide()
}
})
}
}
@@ -349,6 +351,29 @@ func setUpSearchEntry() *gtk.SearchEntry {
fileSearchResultWrapper.Hide()
}
}
// focus 1st search result #17
var w *gtk.Widget
if appFlowBox != nil {
b := appFlowBox.GetChildAtIndex(0)
if b != nil {
button, err := b.GetChild()
if err == nil {
button.ToWidget().GrabFocus()
w = button.ToWidget()
}
}
}
if w == nil && fileSearchResultFlowBox != nil {
f := fileSearchResultFlowBox.GetChildAtIndex(0)
if f != nil {
//f.SetCanFocus(false)
button, err := f.GetChild()
if err == nil {
button.ToWidget().SetCanFocus(true)
button.ToWidget().GrabFocus()
}
}
}
} else {
// clear search results
appFlowBox = setUpAppsFlowBox(nil, "")
@@ -362,9 +387,9 @@ func setUpSearchEntry() *gtk.SearchEntry {
}
}
})
searchEntry.Connect("focus-in-event", func() {
/*searchEntry.Connect("focus-in-event", func() {
searchEntry.SetText("")
})
})*/
return searchEntry
}
@@ -387,7 +412,8 @@ func searchUserDir(dir string) {
}
fileSearchResultFlowBox.Hide()
statusLabel.SetText(fmt.Sprintf("%v results", fileSearchResultFlowBox.GetChildren().Length()))
statusLabel.SetText(fmt.Sprintf("%v results | LMB: xdg-open | RMB: file manager",
fileSearchResultFlowBox.GetChildren().Length()))
num := uint(fileSearchResultFlowBox.GetChildren().Length() / *fsColumns)
fileSearchResultFlowBox.SetMinChildrenPerLine(num + 1)
fileSearchResultFlowBox.SetMaxChildrenPerLine(num + 1)
@@ -406,6 +432,7 @@ func setUpUserDirButton(iconName, displayName, entryName string, userDirsMap map
}
box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
button, _ := gtk.ButtonNew()
button.SetAlwaysShowImage(true)
img, _ := gtk.ImageNewFromIconName(iconName, gtk.ICON_SIZE_MENU)
button.SetImage(img)
@@ -414,8 +441,16 @@ func setUpUserDirButton(iconName, displayName, entryName string, userDirsMap map
}
button.SetLabel(displayName)
button.Connect("clicked", func() {
launch(fmt.Sprintf("%s %s", *fileManager, userDirsMap[entryName]), false)
button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool {
btnEvent := gdk.EventButtonNewFromEvent(e)
if btnEvent.Button() == 1 {
open(userDirsMap[entryName], true)
return true
} else if btnEvent.Button() == 3 {
open(userDirsMap[entryName], false)
return true
}
return false
})
box.PackStart(button, false, true, 0)
@@ -430,6 +465,7 @@ func setUpUserFileSearchResultButton(fileName, filePath string) *gtk.Box {
if strings.HasPrefix(filePath, "#is_dir#") {
filePath = filePath[8:]
img, _ := gtk.ImageNewFromIconName("folder", gtk.ICON_SIZE_MENU)
button.SetAlwaysShowImage(true)
button.SetImage(img)
}
@@ -443,8 +479,20 @@ func setUpUserFileSearchResultButton(fileName, filePath string) *gtk.Box {
button.SetTooltipText(tooltipText)
}
button.Connect("clicked", func() {
open(filePath)
button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool {
btnEvent := gdk.EventButtonNewFromEvent(e)
if btnEvent.Button() == 1 {
open(filePath, true)
return true
} else if btnEvent.Button() == 3 {
open(filePath, false)
return true
}
return false
})
button.Connect("activate", func() {
open(filePath, true)
})
box.PackStart(button, false, true, 0)