31 Commits

Author SHA1 Message Date
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
Piotr Miller
399cf7fa3a Merge pull request #13 from nwg-piotr/files
hot fix to opening files with file manager
2021-08-17 22:35:43 +02:00
piotr
aefe2af4d5 hot fix to opening files 2021-08-17 22:34:28 +02:00
piotr
71892c25ed update README 2021-08-17 13:11:07 +02:00
piotr
2536331184 update README 2021-08-17 13:06:24 +02:00
Piotr Miller
6ac486a32c Merge pull request #12 from nwg-piotr/chrome
bug fixes and new arguments
2021-08-17 01:25:13 +02:00
piotr
875e7cac4a Quit immediately on window click 2021-08-17 00:54:52 +02:00
piotr
2960603462 -nofs to disable file search 2021-08-16 23:26:30 +02:00
piotr
f9e9608dfc -nocats to disable filtering by categories 2021-08-16 22:41:13 +02:00
piotr
83caef28f6 fresh binary 2021-08-15 14:37:06 +02:00
piotr
d732e9e070 support env vars at the end of the command #11 2021-08-15 14:34:25 +02:00
piotr
033a4d59ae refresh binary 2021-07-21 02:07:35 +02:00
Piotr Miller
97be33094f Merge pull request #9 from nwg-piotr/force_img
SetAlwaysShowImage(true) in category button
2021-07-21 01:55:17 +02:00
piotr
e5246a13cd force image in category button #8 2021-07-21 01:52:19 +02:00
piotr
897d693d62 force image in category button 2021-07-21 01:49:34 +02:00
Piotr Miller
955429d809 Merge pull request #7 from nwg-piotr/fix_pinned
Fix GTK critical warnings on pinned cache file not found
2021-07-12 23:32:41 +02:00
piotr
4bf82d9a98 bump to 0.1.4 2021-07-12 23:26:26 +02:00
piotr
eb358b24cd fix GTK warnings on pinned cache not found #6 2021-07-12 23:23:52 +02:00
5 changed files with 183 additions and 45 deletions

View File

@@ -5,7 +5,8 @@ This application is a part of the [nwg-shell](https://github.com/nwg-piotr/nwg-s
Nwg-drawer is a golang replacement to the `nwggrid` command Nwg-drawer is a golang replacement to the `nwggrid` command
(a part of [nwg-launchers](https://github.com/nwg-piotr/nwg-launchers)). It's being developed with (a part of [nwg-launchers](https://github.com/nwg-piotr/nwg-launchers)). It's being developed with
[sway](https://github.com/swaywm/sway) in mind, but should also work with other wlroots-based Wayland compositors. [sway](https://github.com/swaywm/sway) in mind, but should also work with other wlroots-based Wayland compositors.
X Window System is not supported. X Window System is not officially supported, but you should be able to use the drawer on some floating
window managers (tested on Openbox).
The `nwg-drawer` command displays the application grid. The search entry allows to look for installed applications, The `nwg-drawer` command displays the application grid. The search entry allows to look for installed applications,
and for files in XDG user directories. The grid view may also be filtered by categories. and for files in XDG user directories. The grid view may also be filtered by categories.
@@ -24,17 +25,18 @@ and `nwggrid`.
### Dependencies ### Dependencies
- go 1.16 (just to build) - go >=1.16 (just to build)
- gtk3 - gtk3
- gtk-layer-shell - gtk-layer-shell
- xdg-utils
Optional (recommended): Optional (recommended):
- thunar - thunar
- alacritty - alacritty
You may use another file manager and terminal emulator (see command line arguments), but for now the program has You may use another file manager and terminal emulator (see command line arguments), but mentioned above have been
only been tested with the two mentioned above. confirmed to work well with the program. Also see **Files** below.
### Steps ### Steps
@@ -63,6 +65,10 @@ Usage of nwg-drawer:
Icon Size (default 64) Icon Size (default 64)
-lang string -lang string
force lang, e.g. "en", "pl" force lang, e.g. "en", "pl"
-nocats
Disable filtering by category
-nofs
Disable file search
-o string -o string
name of the Output to display the drawer on (sway only) name of the Output to display the drawer on (sway only)
-ovl -ovl
@@ -80,6 +86,37 @@ Usage of nwg-drawer:
Edit `~/.config/nwg-panel/drawer.css` to your taste. 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 ## Credits
This program uses some great libraries: This program uses some great libraries:

Binary file not shown.

60
main.go
View File

@@ -19,7 +19,7 @@ import (
"github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/gtk"
) )
const version = "0.1.3" const version = "0.1.8"
var ( var (
appDirs []string appDirs []string
@@ -28,6 +28,7 @@ var (
pinned []string pinned []string
src glib.SourceHandle src glib.SourceHandle
id2entry map[string]desktopEntry id2entry map[string]desktopEntry
preferredApps map[string]interface{}
) )
var categoryNames = [...]string{ var categoryNames = [...]string{
@@ -90,6 +91,7 @@ var (
fileSearchResultWrapper *gtk.Box fileSearchResultWrapper *gtk.Box
pinnedFlowBox *gtk.FlowBox pinnedFlowBox *gtk.FlowBox
pinnedFlowBoxWrapper *gtk.Box pinnedFlowBoxWrapper *gtk.Box
categoriesWrapper *gtk.Box
catButtons []*gtk.Button catButtons []*gtk.Button
statusLabel *gtk.Label statusLabel *gtk.Label
status string status string
@@ -109,6 +111,8 @@ var lang = flag.String("lang", "", "force lang, e.g. \"en\", \"pl\"")
var fileManager = flag.String("fm", "thunar", "File Manager") var fileManager = flag.String("fm", "thunar", "File Manager")
var term = flag.String("term", "alacritty", "Terminal emulator") var term = flag.String("term", "alacritty", "Terminal emulator")
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 noFS = flag.Bool("nofs", false, "Disable file search")
func main() { func main() {
timeStart := time.Now() timeStart := time.Now()
@@ -172,6 +176,7 @@ func main() {
if err != nil { if err != nil {
pinned = nil pinned = nil
} }
println(fmt.Sprintf("Found %v pinned items", len(pinned)))
cssFile := filepath.Join(configDirectory, *cssFileName) cssFile := filepath.Join(configDirectory, *cssFileName)
@@ -184,6 +189,17 @@ func main() {
status = parseDesktopFiles(desktopFiles) 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))
fmt.Println(preferredApps)
}
// USER INTERFACE // USER INTERFACE
gtk.Init(nil) gtk.Init(nil)
@@ -253,7 +269,6 @@ func main() {
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,
gdk.KEY_Return, gdk.KEY_Page_Up, gdk.KEY_Page_Down, gdk.KEY_Home, gdk.KEY_End: gdk.KEY_Return, gdk.KEY_Page_Up, gdk.KEY_Page_Down, gdk.KEY_Home, gdk.KEY_End:
//searchEntry.SetText("")
return false return false
default: default:
@@ -298,10 +313,12 @@ func main() {
searchEntry.SetMaxWidthChars(30) searchEntry.SetMaxWidthChars(30)
searchBoxWrapper.PackStart(searchEntry, true, false, 0) searchBoxWrapper.PackStart(searchEntry, true, false, 0)
categoriesWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) if !*noCats {
categoriesButtonBox := setUpCategoriesButtonBox() categoriesWrapper, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
categoriesWrapper.PackStart(categoriesButtonBox, true, false, 0) categoriesButtonBox := setUpCategoriesButtonBox()
outerVBox.PackStart(categoriesWrapper, false, false, 0) categoriesWrapper.PackStart(categoriesButtonBox, true, false, 0)
outerVBox.PackStart(categoriesWrapper, false, false, 0)
}
pinnedWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) pinnedWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
outerVBox.PackStart(pinnedWrapper, false, false, 0) outerVBox.PackStart(pinnedWrapper, false, false, 0)
@@ -311,10 +328,19 @@ func main() {
pinnedFlowBox = setUpPinnedFlowBox() pinnedFlowBox = setUpPinnedFlowBox()
resultWindow, _ = gtk.ScrolledWindowNew(nil, nil) resultWindow, _ = gtk.ScrolledWindowNew(nil, nil)
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 {
btnEvent := gdk.EventButtonNewFromEvent(e)
if btnEvent.Button() == 1 || btnEvent.Button() == 3 {
gtk.MainQuit()
return true
}
return false
})
outerVBox.PackStart(resultWindow, true, true, 10) outerVBox.PackStart(resultWindow, true, true, 10)
resultsWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) resultsWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
@@ -341,11 +367,13 @@ func main() {
resultsWrapper.PackStart(placeholder, true, true, 0) resultsWrapper.PackStart(placeholder, true, true, 0)
placeholder.SetSizeRequest(20, 20) placeholder.SetSizeRequest(20, 20)
wrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) if !*noFS {
fileSearchResultWrapper, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) wrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
fileSearchResultWrapper.SetProperty("name", "files-box") fileSearchResultWrapper, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
wrapper.PackStart(fileSearchResultWrapper, true, false, 0) fileSearchResultWrapper.SetProperty("name", "files-box")
resultsWrapper.PackEnd(wrapper, false, false, 10) wrapper.PackStart(fileSearchResultWrapper, true, false, 0)
resultsWrapper.PackEnd(wrapper, false, false, 10)
}
statusLineWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) statusLineWrapper, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0)
outerVBox.PackStart(statusLineWrapper, false, false, 10) outerVBox.PackStart(statusLineWrapper, false, false, 10)
@@ -353,9 +381,13 @@ func main() {
statusLineWrapper.PackStart(statusLabel, true, false, 0) statusLineWrapper.PackStart(statusLabel, true, false, 0)
win.ShowAll() win.ShowAll()
fileSearchResultWrapper.SetSizeRequest(appFlowBox.GetAllocatedWidth(), 1) if !*noFS {
categoriesWrapper.SetSizeRequest(1, categoriesWrapper.GetAllocatedHeight()*2) fileSearchResultWrapper.SetSizeRequest(appFlowBox.GetAllocatedWidth(), 1)
fileSearchResultWrapper.Hide() fileSearchResultWrapper.Hide()
}
if !*noCats {
categoriesWrapper.SetSizeRequest(1, categoriesWrapper.GetAllocatedHeight()*2)
}
t := time.Now() t := time.Now()
println(fmt.Sprintf("UI created in %v ms. Thank you for your patience.", t.Sub(timeStart).Milliseconds())) println(fmt.Sprintf("UI created in %v ms. Thank you for your patience.", t.Sub(timeStart).Milliseconds()))

View File

@@ -2,6 +2,8 @@ package main
import ( import (
"context" "context"
"encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
@@ -10,6 +12,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp"
"sort" "sort"
"strings" "strings"
"time" "time"
@@ -243,6 +246,25 @@ func getAppDirs() []string {
return dirs 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) { func listFiles(dir string) ([]fs.FileInfo, error) {
files, err := ioutil.ReadDir(dir) files, err := ioutil.ReadDir(dir)
if err == nil { if err == nil {
@@ -583,17 +605,19 @@ func launch(command string, terminal bool) {
envVarsNum := strings.Count(command, "=") envVarsNum := strings.Count(command, "=")
var envVars []string var envVars []string
cmdIdx := 0 cmdIdx := -1
lastEnvVarIdx := 0
if envVarsNum > 0 { if envVarsNum > 0 {
for idx, item := range elements { for idx, item := range elements {
if strings.Contains(item, "=") { if strings.Contains(item, "=") {
lastEnvVarIdx = idx
envVars = append(envVars, item) envVars = append(envVars, item)
} else if !strings.HasPrefix(item, "-") && cmdIdx == -1 {
cmdIdx = idx
} }
} }
cmdIdx = lastEnvVarIdx + 1 }
if cmdIdx == -1 {
cmdIdx = 0
} }
cmd := exec.Command(elements[cmdIdx], elements[1+cmdIdx:]...) cmd := exec.Command(elements[cmdIdx], elements[1+cmdIdx:]...)
@@ -620,14 +644,25 @@ func launch(command string, terminal bool) {
}) })
} }
func open(filePath string) { func open(filePath string, xdgOpen bool) {
cmd := exec.Command(*fileManager, filePath) var cmd *exec.Cmd
go cmd.Run() 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()
gtk.MainQuit()
return false
})
} }
// Returns map output name -> gdk.Monitor // Returns map output name -> gdk.Monitor

View File

@@ -17,7 +17,7 @@ func setUpPinnedFlowBox() *gtk.FlowBox {
flowBox, _ := gtk.FlowBoxNew() flowBox, _ := gtk.FlowBoxNew()
if uint(len(pinned)) >= *columnsNumber { if uint(len(pinned)) >= *columnsNumber {
flowBox.SetMaxChildrenPerLine(*columnsNumber) flowBox.SetMaxChildrenPerLine(*columnsNumber)
} else { } else if len(pinned) > 0 {
flowBox.SetMaxChildrenPerLine(uint(len(pinned))) flowBox.SetMaxChildrenPerLine(uint(len(pinned)))
} }
@@ -78,16 +78,17 @@ func setUpPinnedFlowBox() *gtk.FlowBox {
}) })
flowBox.Add(btn) flowBox.Add(btn)
} }
pinnedFlowBoxWrapper.PackStart(flowBox, true, false, 0)
//While moving focus with arrow keys we want buttons to get focus directly
flowBox.GetChildren().Foreach(func(item interface{}) {
item.(*gtk.Widget).SetCanFocus(false)
})
} }
flowBox.Connect("enter-notify-event", func() { flowBox.Connect("enter-notify-event", func() {
cancelClose() cancelClose()
}) })
pinnedFlowBoxWrapper.PackStart(flowBox, true, false, 0)
//While moving focus with arrow keys we want buttons to get focus directly
flowBox.GetChildren().Foreach(func(item interface{}) {
item.(*gtk.Widget).SetCanFocus(false)
})
flowBox.ShowAll() flowBox.ShowAll()
return flowBox return flowBox
@@ -130,6 +131,8 @@ func setUpCategoriesButtonBox() *gtk.EventBox {
button.SetProperty("name", "category-button") button.SetProperty("name", "category-button")
catButtons = append(catButtons, button) catButtons = append(catButtons, button)
button.SetLabel(cat.DisplayName) button.SetLabel(cat.DisplayName)
// fix #8
button.SetAlwaysShowImage(true)
hBox.PackStart(button, false, false, 0) hBox.PackStart(button, false, false, 0)
name := cat.Name name := cat.Name
b := *button b := *button
@@ -143,7 +146,9 @@ func setUpCategoriesButtonBox() *gtk.EventBox {
w := b.GetAllocatedWidth() w := b.GetAllocatedWidth()
b.SetImagePosition(gtk.POS_TOP) b.SetImagePosition(gtk.POS_TOP)
b.SetSizeRequest(w, 0) b.SetSizeRequest(w, 0)
fileSearchResultWrapper.Hide() if fileSearchResultWrapper != nil {
fileSearchResultWrapper.Hide()
}
}) })
} }
} }
@@ -316,13 +321,17 @@ func setUpSearchEntry() *gtk.SearchEntry {
phrase, _ = searchEntry.GetText() phrase, _ = searchEntry.GetText()
if len(phrase) > 0 { if len(phrase) > 0 {
// search apps
appFlowBox = setUpAppsFlowBox(nil, phrase) appFlowBox = setUpAppsFlowBox(nil, phrase)
if len(phrase) > 2 { // search files
if !*noFS && len(phrase) > 2 {
if fileSearchResultFlowBox != nil { if fileSearchResultFlowBox != nil {
fileSearchResultFlowBox.Destroy() fileSearchResultFlowBox.Destroy()
} }
fileSearchResultFlowBox = setUpFileSearchResultContainer() fileSearchResultFlowBox = setUpFileSearchResultContainer()
for key := range userDirsMap { for key := range userDirsMap {
if key != "home" { if key != "home" {
fileSearchResults = nil fileSearchResults = nil
@@ -334,17 +343,25 @@ func setUpSearchEntry() *gtk.SearchEntry {
statusLabel.SetText("0 results") statusLabel.SetText("0 results")
} }
} else { } else {
// search phrase too short
if fileSearchResultFlowBox != nil { if fileSearchResultFlowBox != nil {
fileSearchResultFlowBox.Destroy() fileSearchResultFlowBox.Destroy()
} }
fileSearchResultWrapper.Hide() if fileSearchResultWrapper != nil {
fileSearchResultWrapper.Hide()
}
} }
} else { } else {
// clear search results
appFlowBox = setUpAppsFlowBox(nil, "")
if fileSearchResultFlowBox != nil { if fileSearchResultFlowBox != nil {
fileSearchResultFlowBox.Destroy() fileSearchResultFlowBox.Destroy()
} }
appFlowBox = setUpAppsFlowBox(nil, "")
fileSearchResultWrapper.Hide() if fileSearchResultWrapper != nil {
fileSearchResultWrapper.Hide()
}
} }
}) })
searchEntry.Connect("focus-in-event", func() { searchEntry.Connect("focus-in-event", func() {
@@ -372,7 +389,8 @@ func searchUserDir(dir string) {
} }
fileSearchResultFlowBox.Hide() 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) num := uint(fileSearchResultFlowBox.GetChildren().Length() / *fsColumns)
fileSearchResultFlowBox.SetMinChildrenPerLine(num + 1) fileSearchResultFlowBox.SetMinChildrenPerLine(num + 1)
fileSearchResultFlowBox.SetMaxChildrenPerLine(num + 1) fileSearchResultFlowBox.SetMaxChildrenPerLine(num + 1)
@@ -399,8 +417,16 @@ func setUpUserDirButton(iconName, displayName, entryName string, userDirsMap map
} }
button.SetLabel(displayName) button.SetLabel(displayName)
button.Connect("clicked", func() { button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool {
launch(fmt.Sprintf("%s %s", *fileManager, userDirsMap[entryName]), false) 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) box.PackStart(button, false, true, 0)
@@ -428,8 +454,16 @@ func setUpUserFileSearchResultButton(fileName, filePath string) *gtk.Box {
button.SetTooltipText(tooltipText) button.SetTooltipText(tooltipText)
} }
button.Connect("clicked", func() { button.Connect("button-release-event", func(btn *gtk.Button, e *gdk.Event) bool {
open(filePath) 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
}) })
box.PackStart(button, false, true, 0) box.PackStart(button, false, true, 0)