Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a55c82483a | |||
| 9e9bb82025 | |||
| ea91d3cd80 | |||
| 2a0d53db09 | |||
| a0213d1886 | |||
| 695ce815d9 | |||
| 01556c1eb0 | |||
| d7410bb88f | |||
| bc63e6d10f | |||
| 0403825c3d | |||
| 0f1bb3fabd | |||
| 78c6842fab | |||
| dc1edbad3a | |||
| 6dd00c5f8f | |||
| e68337886f | |||
| 3b639f53fd | |||
| 3199ad88fd | |||
| a221d18d33 | |||
| a9eeb3bb1c | |||
| 844a282fd7 | |||
| 9da352a315 | |||
| 34b8f7c926 | |||
| 5d5cedec58 | |||
| 8441a8b752 | |||
| d64d88e0a5 | |||
| 5eeb9cc702 | |||
| fc3411e568 | |||
| 77ce9e8ad4 | |||
| 63dd8ebb83 | |||
| 7cf45c9ac8 | |||
| 2f8de0bed2 | |||
| 67ca030bb2 |
@@ -1,11 +1,16 @@
|
|||||||
# LinuxPA
|
# LinuxPA
|
||||||
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
|
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
|
||||||
|
|
||||||
# App Detection
|
# How to use
|
||||||
LinuxPA looks in all folders in the PortableApps folder for, first, a script file (starts with the shebang (`#!`)) and, secondly, a native linux executable (starts with ELF). It will only add the first one it finds.
|
Just double click on an app to launch it! If there are multiple executables, you can either select the specific executable, or if you just double click the app it'll launch the first linux executable (.sh script files have priority), but if one isn't found it launches the first executable in general.
|
||||||
|
|
||||||
|
# Apps:
|
||||||
|
Both of the below places provide linux executables that don't need libs installed on the host system:
|
||||||
|
[AppImage](https://bintray.com/probono/AppImages)
|
||||||
|
|
||||||
# PortableApps.com Compatibility
|
# PortableApps.com Compatibility
|
||||||
LinuxPA works will with the PortableApps.com launcher, as it looks for apps in the PortableApps folder and grabs the app's name and icon from where it should be in the PortableApps.com format.
|
LinuxPA works will with the PortableApps.com launcher, as it looks for apps in the PortableApps folder and grabs the app's name and icon from where it should be in the PortableApps.com format.
|
||||||
|
My forum at PortableApps.com can be found [here](http://portableapps.com/node/54998).
|
||||||
|
|
||||||
# common.sh
|
# common.sh
|
||||||
common.sh is found in the PortableApps/LinuxPACom folder and is executed before the app. I mainly use it to set environment variables (such as HOME).
|
common.sh is found in the PortableApps/LinuxPACom folder and is executed before the app. I mainly use it to set environment variables (such as HOME).
|
||||||
@@ -15,17 +20,16 @@ Because apps aren't natively formated in the PortableApps.com format, if LinuxPA
|
|||||||
|
|
||||||
# AppImage Support
|
# AppImage Support
|
||||||
[AppImage Website](http://appimage.org)
|
[AppImage Website](http://appimage.org)
|
||||||
Right now AppImages are simply supported via the native linux executable support, but later I'm hoping to add downloading and automatic updating support.
|
Right now AppImages are simply supported via the native linux executable support, but later I'm hoping to add downloading and automatic updating support later on.
|
||||||
|
|
||||||
# USB mount
|
# USB mount
|
||||||
Unfortunately Linux, by default, doesn't support running executables off of flash drives, requiring you to mount your drive with special mount arguments, I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
|
Unfortunately Linux, by default, doesn't support running executables off of FAT formated flash drives, requiring you to mount your drive with special mount arguments or format in a linux friendly format (such as EXT4). I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
|
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
|
||||||
|
|
||||||
# TODO (Might be in order)
|
# TODO (Might be in order)
|
||||||
1. MAKE IT BETTER
|
1. MAKE IT BETTER
|
||||||
1. Add settings menu
|
|
||||||
1. Add updater for .AppImage files
|
1. Add updater for .AppImage files
|
||||||
1. Download .AppImage files (maybe)
|
1. Download .AppImage files (maybe)
|
||||||
1. Check if all apps are closed when it closes and ask if you want to force stop the apps.
|
1. Check if all apps are closed when it closes and ask if you want to force stop the apps.
|
||||||
|
|||||||
@@ -0,0 +1,281 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type app struct {
|
||||||
|
name string
|
||||||
|
cat string
|
||||||
|
appimg []string
|
||||||
|
lin []string
|
||||||
|
ex []string
|
||||||
|
icon *gdk.Pixbuf
|
||||||
|
dir string
|
||||||
|
ini *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter {
|
||||||
|
it := store.Append(nil)
|
||||||
|
store.SetValue(it, 0, a.icon)
|
||||||
|
store.SetValue(it, 1, a.name)
|
||||||
|
if len(a.ex) > 1 {
|
||||||
|
if wine {
|
||||||
|
for _, v := range a.ex {
|
||||||
|
i := store.Append(it)
|
||||||
|
store.SetValue(i, 1, v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range a.lin {
|
||||||
|
i := store.Append(it)
|
||||||
|
store.SetValue(i, 1, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) launch() {
|
||||||
|
if len(a.ex) == 1 {
|
||||||
|
if wine {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if !contains(a.lin, a.ex[0]) {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if wine {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if len(a.lin) == 0 {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var ind int
|
||||||
|
for i, v := range a.lin {
|
||||||
|
if strings.HasSuffix(v, ".sh") {
|
||||||
|
ind = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
if len(a.lin) != 0 {
|
||||||
|
var ind int
|
||||||
|
for i, v := range a.lin {
|
||||||
|
if strings.HasSuffix(v, ".sh") {
|
||||||
|
ind = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) launchSub(sub int) {
|
||||||
|
if wine {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if !contains(a.lin, a.ex[sub]) {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if comEnbld {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||||
|
}
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) edit(parent *gtk.Window, reload func()) {
|
||||||
|
tmp := *a
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
cats = make([]string, 0)
|
||||||
|
lin = make([]string, 0)
|
||||||
|
setup()
|
||||||
|
reload()
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
win.SetDefaultSize(400, 135)
|
||||||
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
topLvl.SetMarginStart(10)
|
||||||
|
topLvl.SetMarginEnd(10)
|
||||||
|
topLvl.SetMarginTop(10)
|
||||||
|
topLvl.SetMarginBottom(10)
|
||||||
|
top, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
img, _ := gtk.ImageNewFromPixbuf(a.icon)
|
||||||
|
imgBut, _ := gtk.ButtonNew()
|
||||||
|
imgBut.SetImage(img)
|
||||||
|
imgBut.SetSizeRequest(100, 100)
|
||||||
|
imgBut.Connect("clicked", func() {
|
||||||
|
fil, _ := gtk.FileChooserDialogNewWith2Buttons("Select Icon", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Cancel", gtk.RESPONSE_CANCEL, "Open", gtk.RESPONSE_ACCEPT)
|
||||||
|
filter, _ := gtk.FileFilterNew()
|
||||||
|
filter.AddPixbufFormats()
|
||||||
|
filter.SetName("Supported Pictures")
|
||||||
|
fil.AddFilter(filter)
|
||||||
|
resp := fil.Run()
|
||||||
|
if resp == int(gtk.RESPONSE_ACCEPT) {
|
||||||
|
filename := fil.GetFilename()
|
||||||
|
_, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pix, _ := gdk.PixbufNewFromFileAtSize(filename, 32, 32)
|
||||||
|
tmp.icon = pix
|
||||||
|
img.SetFromPixbuf(pix)
|
||||||
|
fil.Close()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
topRt, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
nameLbl, _ := gtk.LabelNew("Name:")
|
||||||
|
nameLbl.SetHAlign(gtk.ALIGN_START)
|
||||||
|
txtgtbl, _ := gtk.TextTagTableNew()
|
||||||
|
txtBuf, _ := gtk.TextBufferNew(txtgtbl)
|
||||||
|
nameTxt, _ := gtk.TextViewNewWithBuffer(txtBuf)
|
||||||
|
nameTxt.SetAcceptsTab(false)
|
||||||
|
nameTxt.SetWrapMode(gtk.WRAP_CHAR)
|
||||||
|
nameTxt.SetPixelsBelowLines(5)
|
||||||
|
nameTxt.SetHExpand(true)
|
||||||
|
nameTxt.SetVExpand(false)
|
||||||
|
nameTxt.SetBorderWindowSize(gtk.TEXT_WINDOW_BOTTOM, 5)
|
||||||
|
txtBuf.SetText(tmp.name)
|
||||||
|
vScrollName, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScrollName, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
nameScr, _ := gtk.ScrolledWindowNew(hScrollName, vScrollName)
|
||||||
|
nameScr.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
|
||||||
|
nameScr.SetSizeRequest(300, 25)
|
||||||
|
nameScr.SetVExpand(false)
|
||||||
|
nameScr.Add(nameTxt)
|
||||||
|
catLbl, _ := gtk.LabelNew("Category:")
|
||||||
|
catLbl.SetHAlign(gtk.ALIGN_START)
|
||||||
|
catTbl, _ := gtk.TextTagTableNew()
|
||||||
|
catBuf, _ := gtk.TextBufferNew(catTbl)
|
||||||
|
catTxt, _ := gtk.TextViewNewWithBuffer(catBuf)
|
||||||
|
catBuf.SetText(tmp.cat)
|
||||||
|
catTxt.SetAcceptsTab(false)
|
||||||
|
catTxt.SetWrapMode(gtk.WRAP_CHAR)
|
||||||
|
catTxt.SetPixelsBelowLines(5)
|
||||||
|
catTxt.SetHExpand(true)
|
||||||
|
catTxt.SetVExpand(false)
|
||||||
|
catTxt.SetBorderWindowSize(gtk.TEXT_WINDOW_BOTTOM, 5)
|
||||||
|
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
catScr, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
|
||||||
|
catScr.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
|
||||||
|
catScr.SetSizeRequest(300, 25)
|
||||||
|
catScr.SetVExpand(false)
|
||||||
|
catScr.Add(catTxt)
|
||||||
|
topRt.Add(nameLbl)
|
||||||
|
topRt.Add(nameScr)
|
||||||
|
topRt.Add(catLbl)
|
||||||
|
topRt.Add(catScr)
|
||||||
|
top.Add(imgBut)
|
||||||
|
top.Add(topRt)
|
||||||
|
bot, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
sv, _ := gtk.ButtonNewWithLabel("Save")
|
||||||
|
sv.Connect("clicked", func() {
|
||||||
|
tmp.name, _ = txtBuf.GetText(txtBuf.GetStartIter(), txtBuf.GetEndIter(), true)
|
||||||
|
tmp.cat, _ = catBuf.GetText(catBuf.GetStartIter(), catBuf.GetEndIter(), true)
|
||||||
|
tmp.makeIni()
|
||||||
|
os.Remove(a.dir + "/appicon.png")
|
||||||
|
tmp.icon.SavePNG(a.dir+"/appicon.png", 0)
|
||||||
|
win.Close()
|
||||||
|
})
|
||||||
|
cnl, _ := gtk.ButtonNewWithLabel("Cancel")
|
||||||
|
cnl.Connect("clicked", func() {
|
||||||
|
win.Close()
|
||||||
|
})
|
||||||
|
bot.PackEnd(sv, false, false, 0)
|
||||||
|
bot.PackEnd(cnl, false, false, 0)
|
||||||
|
topLvl.Add(top)
|
||||||
|
topLvl.Add(bot)
|
||||||
|
win.Add(topLvl)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *app) makeIni() {
|
||||||
|
os.Remove(a.dir + "/appinfo.ini")
|
||||||
|
fil, err := os.Create(a.dir + "/appinfo.ini")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ini := "[General]\n"
|
||||||
|
ini += "Category=" + a.cat + "\n"
|
||||||
|
ini += "Name=" + a.name + "\n"
|
||||||
|
wrt := bufio.NewWriter(fil)
|
||||||
|
wrt.WriteString(ini)
|
||||||
|
wrt.Flush()
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
|
func convert(in string) (out []tag) {
|
||||||
|
for i := 0; i < len(in); i++ {
|
||||||
|
v := in[i]
|
||||||
|
if v == '<' {
|
||||||
|
for j := i; j < len(in); j++ {
|
||||||
|
val := in[j]
|
||||||
|
if val == '>' {
|
||||||
|
var tmp tag
|
||||||
|
tmp.process(in[i+1 : j+1])
|
||||||
|
if !tmp.end && tmp.typ == "a" {
|
||||||
|
tmp.index[0] = i
|
||||||
|
tmp.index[1] = j
|
||||||
|
nd := fndend(tmp, in[j+1:])
|
||||||
|
if !reflect.DeepEqual(nd, tag{}) {
|
||||||
|
tmp.Meat = in[j+1 : nd.index[0]]
|
||||||
|
out = append(out, tmp)
|
||||||
|
str := in[tmp.index[1]:nd.index[0]]
|
||||||
|
in = in[:i] + str + in[nd.index[1]+1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func fndend(fnt tag, area string) tag {
|
||||||
|
var count int
|
||||||
|
for i, v := range area {
|
||||||
|
if v == '<' {
|
||||||
|
for j, val := range area[i:] {
|
||||||
|
if val == '>' {
|
||||||
|
var tmp tag
|
||||||
|
tmp.process(area[i+1 : i+j+1])
|
||||||
|
if tmp.typ == fnt.typ {
|
||||||
|
if tmp.end {
|
||||||
|
if count == 0 {
|
||||||
|
tmp.index[0] = fnt.index[1] + 1 + i
|
||||||
|
tmp.index[1] = fnt.index[1] + j + i + 1
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
count--
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
count++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tag{}
|
||||||
|
}
|
||||||
+115
@@ -0,0 +1,115 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type tag struct {
|
||||||
|
typ string
|
||||||
|
end bool
|
||||||
|
params map[string]string
|
||||||
|
index [2]int
|
||||||
|
Meat string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) value(param string) string {
|
||||||
|
return t.params[param]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) setValue(param, value string) {
|
||||||
|
if t.params == nil {
|
||||||
|
t.params = make(map[string]string)
|
||||||
|
}
|
||||||
|
t.params[strings.TrimSpace(strings.ToLower(param))] = strings.TrimSpace(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) process(bbtag string) {
|
||||||
|
if strings.HasPrefix(bbtag, "/") {
|
||||||
|
t.end = true
|
||||||
|
t.typ = strings.ToLower(strings.TrimPrefix(bbtag[:len(bbtag)-1], "/"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i, v := range bbtag {
|
||||||
|
if v == '=' || v == ' ' || v == '>' {
|
||||||
|
t.typ = strings.ToLower(bbtag[:i])
|
||||||
|
switch v {
|
||||||
|
case '=':
|
||||||
|
if qt := bbtag[i+1]; qt == '\'' || qt == '"' {
|
||||||
|
for j := i + 2; j < len(bbtag); j++ {
|
||||||
|
if bbtag[j] == qt {
|
||||||
|
t.setValue("starting", bbtag[i+2:j])
|
||||||
|
bbtag = bbtag[j+1:]
|
||||||
|
break
|
||||||
|
} else if bbtag[j] == '>' {
|
||||||
|
t.setValue("starting", bbtag[i+2:j])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for j := i + 1; j < len(bbtag); j++ {
|
||||||
|
if bbtag[j] == '>' {
|
||||||
|
t.setValue("starting", bbtag[i+1:j])
|
||||||
|
return
|
||||||
|
} else if bbtag[j] == ' ' {
|
||||||
|
t.setValue("starting", bbtag[i+1:j])
|
||||||
|
bbtag = bbtag[j+1:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '>':
|
||||||
|
return
|
||||||
|
case ' ':
|
||||||
|
bbtag = bbtag[i:]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.processFurther(bbtag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tag) processFurther(further string) {
|
||||||
|
further = strings.TrimSpace(further)
|
||||||
|
for i := 0; i < len(further); i++ {
|
||||||
|
switch further[i] {
|
||||||
|
case ' ':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[:i])
|
||||||
|
further = strings.TrimSpace(further[i:])
|
||||||
|
i = -1
|
||||||
|
case '=':
|
||||||
|
if qt := further[i+1]; qt == '\'' || qt == '"' {
|
||||||
|
outloopqt:
|
||||||
|
for j := i + 2; j < len(further); j++ {
|
||||||
|
switch further[j] {
|
||||||
|
case '>':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+2:j])
|
||||||
|
return
|
||||||
|
case qt:
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+2:j])
|
||||||
|
further = strings.TrimSpace(further[j+1:])
|
||||||
|
i = -1
|
||||||
|
break outloopqt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
outloop:
|
||||||
|
for j := i + 1; j < len(further); j++ {
|
||||||
|
switch further[j] {
|
||||||
|
case '>':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+1:j])
|
||||||
|
return
|
||||||
|
case ' ':
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[i+1:j])
|
||||||
|
further = strings.TrimSpace(further[j:])
|
||||||
|
i = -1
|
||||||
|
break outloop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case '>':
|
||||||
|
if i != 0 {
|
||||||
|
t.setValue(strings.ToLower(further[:i]), further[:i])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
type appimg struct {
|
||||||
|
full string
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newApp(name string) appimg {
|
||||||
|
var out appimg
|
||||||
|
out.full = name
|
||||||
|
return out
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func downloadApp(parent *gtk.Window, ap appimg) {
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
spn, _ := gtk.SpinnerNew()
|
||||||
|
spn.Start()
|
||||||
|
lbl, _ := gtk.LabelNew("Downloading " + ap.full + "...")
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
box.SetMarginStart(10)
|
||||||
|
box.SetMarginEnd(10)
|
||||||
|
box.SetMarginTop(10)
|
||||||
|
box.SetMarginBottom(10)
|
||||||
|
box.Add(spn)
|
||||||
|
box.Add(lbl)
|
||||||
|
win.Add(box)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
go func(win *gtk.Window, ap appimg) {
|
||||||
|
defer win.Close()
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := check.Get(urlBase + ap.full)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
name := strings.Split(ap.full, "-")[0]
|
||||||
|
var foldName string
|
||||||
|
if _, err = os.Open("PortableApps/" + name + "Portable"); err == nil {
|
||||||
|
foldName = "PortableApps/" + name + "Portable"
|
||||||
|
} else if _, err = os.Open("PortableApps/" + name); err == nil {
|
||||||
|
foldName = "PortableApps/" + name
|
||||||
|
} else {
|
||||||
|
os.Mkdir("PortableApps/"+name+"Portable", 0777)
|
||||||
|
foldName = "PortableApps/" + name
|
||||||
|
}
|
||||||
|
os.Remove(foldName + "/" + ap.full)
|
||||||
|
fil, err := os.Create(foldName + "/" + ap.full)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
io.Copy(fil, resp.Body)
|
||||||
|
fil.Chmod(0777)
|
||||||
|
}(win, ap)
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
//Package appimg is for downloading new AppImages for LinuxPA
|
||||||
|
package appimg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
urlBase = "https://dl.bintray.com/probono/AppImages/"
|
||||||
|
)
|
||||||
|
|
||||||
|
//ShowUI shows the list of possible AppImages to be downloaded in a gtk.Window
|
||||||
|
func ShowUI(newestVersionOnly bool, clsFunc func()) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
clsFunc()
|
||||||
|
})
|
||||||
|
apps := make([]appimg, 0)
|
||||||
|
win.SetSizeRequest(400, 400)
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
appList, _ := gtk.ListBoxNew()
|
||||||
|
apch := make(chan appimg)
|
||||||
|
appList.SetHExpand(true)
|
||||||
|
appList.SetVExpand(true)
|
||||||
|
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
lst, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
|
||||||
|
lst.SetSizeRequest(170, 500)
|
||||||
|
lst.Add(appList)
|
||||||
|
box.Add(lst)
|
||||||
|
win.Add(box)
|
||||||
|
appList.Connect("row-activated", func() {
|
||||||
|
if appList.GetSelectedRow().GetIndex() >= 0 {
|
||||||
|
downloadApp(win, apps[appList.GetSelectedRow().GetIndex()])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
getList(win, apch)
|
||||||
|
go func(win *gtk.Window, apch chan appimg, list *gtk.ListBox) {
|
||||||
|
if newestVersionOnly {
|
||||||
|
imgs := make([]appimg, 0)
|
||||||
|
a := make(map[string][]appimg)
|
||||||
|
names := make([]string, 0)
|
||||||
|
for i := range apch {
|
||||||
|
imgs = append(imgs, i)
|
||||||
|
}
|
||||||
|
for i, v := range imgs {
|
||||||
|
sp := strings.Split(v.full, "-")
|
||||||
|
if len(sp) >= 2 {
|
||||||
|
vers := sp[1]
|
||||||
|
removeLetters(vers)
|
||||||
|
imgs[i].version = vers
|
||||||
|
imgs[i].name = sp[0]
|
||||||
|
if _, ok := a[imgs[i].name]; !ok {
|
||||||
|
names = append(names, imgs[i].name)
|
||||||
|
}
|
||||||
|
a[imgs[i].name] = append(a[imgs[i].name], imgs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
for _, name := range names {
|
||||||
|
glib.IdleAdd(func(name string, list *gtk.ListBox, i appimg) {
|
||||||
|
lbl, _ := gtk.LabelNew(name)
|
||||||
|
list.Add(lbl)
|
||||||
|
apps = append(apps, i)
|
||||||
|
lbl.Show()
|
||||||
|
}, name, list, a[name][compareVersions(a[name])])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := range apch {
|
||||||
|
glib.IdleAdd(func(list *gtk.ListBox, i appimg) {
|
||||||
|
lbl, _ := gtk.LabelNew(i.full)
|
||||||
|
list.Add(lbl)
|
||||||
|
apps = append(apps, i)
|
||||||
|
lbl.Show()
|
||||||
|
}, list, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(win, apch, appList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getList(parent *gtk.Window, apch chan appimg) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
win.SetDestroyWithParent(true)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
spin, _ := gtk.SpinnerNew()
|
||||||
|
spin.Start()
|
||||||
|
txt, _ := gtk.LabelNew("Getting List...")
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
box.SetMarginBottom(10)
|
||||||
|
box.SetMarginEnd(10)
|
||||||
|
box.SetMarginStart(10)
|
||||||
|
box.SetMarginTop(10)
|
||||||
|
box.Add(spin)
|
||||||
|
box.Add(txt)
|
||||||
|
win.Add(box)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
go func(win *gtk.Window, apch chan appimg) {
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := check.Get(urlBase)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
close(apch)
|
||||||
|
win.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
btys, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
close(apch)
|
||||||
|
win.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tgs := convert(string(btys))
|
||||||
|
for _, v := range tgs {
|
||||||
|
if strings.HasSuffix(strings.ToLower(v.Meat), ".appimage") {
|
||||||
|
apch <- newApp(v.Meat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(apch)
|
||||||
|
win.Close()
|
||||||
|
}(win, apch)
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func removeLetters(vers string) string {
|
||||||
|
vers = strings.ToLower(vers)
|
||||||
|
letters := []string{"abcdefghijklmnopqrstuvwxyz"}
|
||||||
|
for _, v := range letters {
|
||||||
|
vers = strings.Replace(vers, v, "", -1)
|
||||||
|
}
|
||||||
|
return vers
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package appimg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func compareVersions(imgs []appimg) int {
|
||||||
|
for i := range imgs {
|
||||||
|
imgs[i].version = removeLetters(imgs[i].version)
|
||||||
|
}
|
||||||
|
highest := 0
|
||||||
|
higharr := strings.Split(imgs[0].version, ".")
|
||||||
|
for i := 0; i < len(imgs); i++ {
|
||||||
|
if i != highest {
|
||||||
|
varr := strings.Split(imgs[i].version, ".")
|
||||||
|
if len(higharr) < len(varr) {
|
||||||
|
for j := 0; j < len(higharr); j++ {
|
||||||
|
h, _ := strconv.Atoi(higharr[j])
|
||||||
|
c, _ := strconv.Atoi(varr[j])
|
||||||
|
if h > c {
|
||||||
|
break
|
||||||
|
} else if c > h {
|
||||||
|
highest = i
|
||||||
|
higharr = varr
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return highest
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/nelsam/gxui"
|
||||||
|
"github.com/nelsam/gxui/drivers/gl"
|
||||||
|
"github.com/nelsam/gxui/themes/dark"
|
||||||
|
"github.com/nelsam/gxui/themes/light"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
version = "1.1.0.0"
|
||||||
|
defIni = "[basic]\ntheme=dk"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dr gxui.Driver
|
||||||
|
th gxui.Theme
|
||||||
|
master map[string][]app
|
||||||
|
linmaster map[string][]app
|
||||||
|
cats []string
|
||||||
|
lin []string
|
||||||
|
wine bool
|
||||||
|
comEnbld bool
|
||||||
|
darkTheme = true
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
updated := false
|
||||||
|
os.MkdirAll("PortableApps/LinuxPACom", 0777)
|
||||||
|
stat, err := versionDL()
|
||||||
|
if stat {
|
||||||
|
res := getVersionFileInfo()
|
||||||
|
if res != "Error!" {
|
||||||
|
stat, err = checkForUpdate(res)
|
||||||
|
if stat {
|
||||||
|
downloadUpdate(res)
|
||||||
|
updated = true
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Failed Version File Info")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
if updated {
|
||||||
|
cmd := exec.Command("./LinuxPA")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
gl.StartDriver(appMain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func appMain(dri gxui.Driver) {
|
||||||
|
dr = dri
|
||||||
|
setup()
|
||||||
|
if darkTheme {
|
||||||
|
th = dark.CreateTheme(dr)
|
||||||
|
} else {
|
||||||
|
th = light.CreateTheme(dr)
|
||||||
|
}
|
||||||
|
th = dark.CreateTheme(dr)
|
||||||
|
ui()
|
||||||
|
}
|
||||||
|
|
||||||
|
func contains(arr []string, str string) bool {
|
||||||
|
for _, v := range arr {
|
||||||
|
if v == str {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/draw"
|
||||||
|
_ "image/png"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/nelsam/gxui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
PortableAppsFold, err := os.Open("PortableApps")
|
||||||
|
if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() {
|
||||||
|
os.Mkdir("PortableApps", 0777)
|
||||||
|
PortableAppsFold, err = os.Open("PortableApps")
|
||||||
|
if err != nil {
|
||||||
|
panic("Can't find PortableApps folder and can't create one!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err = os.Open("PortableApps/LinuxPACom"); err != nil {
|
||||||
|
os.Mkdir("PortableApps/LinuxPACom", 0777)
|
||||||
|
}
|
||||||
|
fmt.Println(err)
|
||||||
|
_, err = os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
if err == nil {
|
||||||
|
comEnbld = true
|
||||||
|
}
|
||||||
|
fi, err := os.Open("PortableApps/LinuxPACom/Info.ini")
|
||||||
|
if err != nil {
|
||||||
|
fi, err = os.Create("PortableApps/LinuxPACom/Info.ini")
|
||||||
|
if err == nil {
|
||||||
|
wrt := bufio.NewWriter(fi)
|
||||||
|
wrt.WriteString(defIni)
|
||||||
|
wrt.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
rdr := bufio.NewReader(fi)
|
||||||
|
for err != nil {
|
||||||
|
ln, _, error := rdr.ReadLine()
|
||||||
|
err = error
|
||||||
|
str := string(ln)
|
||||||
|
if strings.HasPrefix(str, "theme=") {
|
||||||
|
str = strings.TrimPrefix(str, "theme=")
|
||||||
|
if str == "lt" {
|
||||||
|
darkTheme = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PAFolds, _ := PortableAppsFold.Readdirnames(-1)
|
||||||
|
sort.Strings(PAFolds)
|
||||||
|
for _, v := range PAFolds {
|
||||||
|
fold, _ := os.Open("PortableApps/" + v)
|
||||||
|
if stat, _ := fold.Stat(); stat.IsDir() && stat.Name() != "PortableApps.com" && stat.Name() != "LinuxPACom" {
|
||||||
|
ap := processApp("PortableApps/" + v)
|
||||||
|
if !reflect.DeepEqual(ap, app{}) {
|
||||||
|
if _, ok := master[ap.cat]; !ok {
|
||||||
|
cats = append(cats, ap.cat)
|
||||||
|
sort.Strings(cats)
|
||||||
|
}
|
||||||
|
if len(ap.lin) != 0 {
|
||||||
|
if _, ok := linmaster[ap.cat]; !ok {
|
||||||
|
lin = append(lin, ap.cat)
|
||||||
|
sort.Strings(lin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
master[ap.cat] = append(master[ap.cat], ap)
|
||||||
|
if len(ap.lin) != 0 {
|
||||||
|
linmaster[ap.cat] = append(linmaster[ap.cat], ap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processApp(fold string) (out app) {
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
out.dir = wd + "/" + fold
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
if out.ini != nil {
|
||||||
|
out.name = getName(out.ini)
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
out.cat = getCat(out.ini)
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
}
|
||||||
|
if out.name == "" {
|
||||||
|
out.name = strings.TrimPrefix(fold, "PortableApps/")
|
||||||
|
}
|
||||||
|
if out.cat == "" {
|
||||||
|
out.cat = "Other"
|
||||||
|
}
|
||||||
|
out.icon = getIcon(fold)
|
||||||
|
folder, _ := os.Open(fold)
|
||||||
|
fis, _ := folder.Readdirnames(-1)
|
||||||
|
for _, v := range fis {
|
||||||
|
tmp, _ := os.Open(fold + "/" + v)
|
||||||
|
if stat, _ := tmp.Stat(); stat.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(strings.ToLower(v), ".appimage") {
|
||||||
|
out.appimg = append(out.appimg, v)
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
out.lin = append(out.lin, v)
|
||||||
|
} else if strings.HasSuffix(strings.ToLower(v), ".exe") {
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
} else {
|
||||||
|
btys := make([]byte, 4)
|
||||||
|
rdr := bufio.NewReader(tmp)
|
||||||
|
rdr.Read(btys)
|
||||||
|
if (strings.Contains(strings.ToLower(string(btys)), "elf") && !strings.HasSuffix(strings.ToLower(v), ".so") && !strings.Contains(v, ".so.")) || strings.HasPrefix(strings.ToLower(string(btys)), "#!") {
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
out.lin = append(out.lin, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(out.ex) == 0 {
|
||||||
|
return app{}
|
||||||
|
}
|
||||||
|
if len(out.lin) == 0 {
|
||||||
|
out.name += " (Wine)"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCat(ini *os.File) string {
|
||||||
|
rdr := bufio.NewReader(ini)
|
||||||
|
var ret string
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
if strings.HasPrefix(string(line), "Category=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "Category=")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdr.Reset(ini)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getName(ini *os.File) string {
|
||||||
|
rdr := bufio.NewReader(ini)
|
||||||
|
var ret string
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
if strings.HasPrefix(string(line), "Name=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "Name=")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdr.Reset(ini)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIcon(fold string) gxui.Texture {
|
||||||
|
var pic *os.File
|
||||||
|
if folder, err := os.Open(fold + "/App/AppInfo"); err == nil {
|
||||||
|
fis, _ := folder.Readdir(-1)
|
||||||
|
var pics []string
|
||||||
|
for _, v := range fis {
|
||||||
|
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".png") && strings.HasPrefix(strings.ToLower(v.Name()), "appicon_") {
|
||||||
|
pics = append(pics, v.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(pics)
|
||||||
|
if len(pics) > 1 {
|
||||||
|
var ind int
|
||||||
|
if !contains(pics, "appicon_32.png") {
|
||||||
|
ind = len(pics) - 1
|
||||||
|
} else {
|
||||||
|
ind = sort.SearchStrings(pics, "appicon_32.png")
|
||||||
|
}
|
||||||
|
pic, _ = os.Open(fold + "/App/AppInfo/" + pics[ind])
|
||||||
|
}
|
||||||
|
} else if fi, err := os.Open(fold + "/appicon.png"); err == nil {
|
||||||
|
pic = fi
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
img, _, err := image.Decode(pic)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
rgba := image.NewRGBA(img.Bounds())
|
||||||
|
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
||||||
|
ret := dr.CreateTexture(rgba, 1)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInfo(fold string) *os.File {
|
||||||
|
tmp, err := os.Open(fold + "/App/AppInfo")
|
||||||
|
if err == nil {
|
||||||
|
fis, _ := tmp.Readdirnames(-1)
|
||||||
|
for _, v := range fis {
|
||||||
|
if strings.ToLower(v) == "appinfo.ini" {
|
||||||
|
tmp, _ := os.Open(fold + "/App/AppInfo/" + v)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if fi, err := os.Open(fold + "/appinfo.ini"); err == nil {
|
||||||
|
return fi
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Executable → Regular
@@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/nelsam/gxui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ui() {
|
||||||
|
catListAdap := &StrList{}
|
||||||
|
appListAdap := &catAdap{}
|
||||||
|
catListAdap.SetStrings(lin)
|
||||||
|
win := th.CreateWindow(500, 500, "LinuxPA")
|
||||||
|
top := th.CreateLinearLayout()
|
||||||
|
top.SetDirection(gxui.BottomToTop)
|
||||||
|
splBox := th.CreateLinearLayout()
|
||||||
|
spl := th.CreateSplitterLayout()
|
||||||
|
spl.SetOrientation(gxui.Horizontal)
|
||||||
|
catList := th.CreateList()
|
||||||
|
catList.SetAdapter(catListAdap)
|
||||||
|
catList.OnSelectionChanged(func(it gxui.AdapterItem) {
|
||||||
|
appListAdap.setCat(it.(string))
|
||||||
|
})
|
||||||
|
appList := th.CreateTree()
|
||||||
|
appList.SetAdapter(appListAdap)
|
||||||
|
spl.AddChild(catList)
|
||||||
|
spl.AddChild(appList)
|
||||||
|
splBox.AddChild(spl)
|
||||||
|
butBox := th.CreateLinearLayout()
|
||||||
|
butBox.SetDirection(gxui.LeftToRight)
|
||||||
|
if _, err := exec.LookPath("wine"); err == nil {
|
||||||
|
wineBut := th.CreateButton()
|
||||||
|
wineBut.SetType(gxui.ToggleButton)
|
||||||
|
wineBut.SetChecked(wine)
|
||||||
|
wineBut.SetText("Show Windows Apps")
|
||||||
|
wineBut.OnClick(func(gxui.MouseEvent) {
|
||||||
|
wine = wineBut.IsChecked()
|
||||||
|
appListAdap.refresh()
|
||||||
|
if wineBut.IsChecked() {
|
||||||
|
catListAdap.SetStrings(cats)
|
||||||
|
wineBut.SetText("Hide Windows Apps")
|
||||||
|
} else {
|
||||||
|
catListAdap.SetStrings(lin)
|
||||||
|
wineBut.SetText("Show Windows Apps")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
_, err := os.Open("Start.exe")
|
||||||
|
if err == nil {
|
||||||
|
pa := th.CreateButton()
|
||||||
|
pa.SetText("Open PortableApps Launcher")
|
||||||
|
pa.OnClick(func(gxui.MouseEvent) {
|
||||||
|
cmd := exec.Command("wine", "Start.exe")
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Start()
|
||||||
|
})
|
||||||
|
butBox.AddChild(pa)
|
||||||
|
}
|
||||||
|
butBox.AddChild(wineBut)
|
||||||
|
}
|
||||||
|
top.AddChild(butBox)
|
||||||
|
top.AddChild(splBox)
|
||||||
|
win.AddChild(top)
|
||||||
|
win.OnClose(dr.Terminate)
|
||||||
|
}
|
||||||
@@ -1,183 +1,104 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"encoding/gob"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nelsam/gxui/drivers/gl"
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
version = "2.1.1.0"
|
||||||
|
defIni = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
appMaster map[string][]prtap
|
master map[string][]app
|
||||||
cats []string
|
linmaster map[string][]app
|
||||||
wineOnly []string
|
cats []string
|
||||||
linOnly []string
|
lin []string
|
||||||
conf *os.File
|
wine bool
|
||||||
common string
|
comEnbld bool
|
||||||
commEnbl bool
|
wineAvail bool
|
||||||
|
portableHide bool
|
||||||
|
versionNewest = true
|
||||||
)
|
)
|
||||||
|
|
||||||
type prtap struct {
|
|
||||||
name string
|
|
||||||
cat string
|
|
||||||
ex string
|
|
||||||
desc string
|
|
||||||
wine bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
commEnbl = true
|
os.MkdirAll("PortableApps/LinuxPACom", 0777)
|
||||||
appMaster = make(map[string][]prtap)
|
master = make(map[string][]app)
|
||||||
os.Mkdir("PortableApps", 0777)
|
linmaster = make(map[string][]app)
|
||||||
os.Mkdir("PortableApps/LinuxPACom", 0777)
|
uiStart()
|
||||||
common = "PortableApps/LinuxPACom/common.sh"
|
}
|
||||||
_, err := os.Open(common)
|
|
||||||
if os.IsNotExist(err) {
|
func uiStart() {
|
||||||
commEnbl = false
|
gtk.Init(nil)
|
||||||
}
|
setup()
|
||||||
pa, err := os.Open("PortableApps")
|
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
fmt.Println("Window not created", err)
|
||||||
}
|
}
|
||||||
appstmp, _ := pa.Readdir(-1)
|
win.SetTitle("LinuxPA")
|
||||||
var folds []string
|
win.Connect("destroy", func() {
|
||||||
for _, v := range appstmp {
|
savePrefs()
|
||||||
if v.IsDir() && v.Name() != "LinuxPACom" && v.Name() != "PortableApps.com" {
|
gtk.MainQuit()
|
||||||
folds = append(folds, v.Name())
|
})
|
||||||
}
|
win.SetDefaultSize(500, 500)
|
||||||
}
|
win.SetPosition(gtk.WIN_POS_CENTER)
|
||||||
sort.Strings(folds)
|
ui(win)
|
||||||
for _, v := range folds {
|
win.ShowAll()
|
||||||
fi, _ := os.Open("PortableApps/" + v)
|
win.Show()
|
||||||
pat := processApp(fi)
|
update(win)
|
||||||
if (pat != prtap{}) {
|
gtk.Main()
|
||||||
if _, ok := appMaster[pat.cat]; !ok {
|
|
||||||
if pat.wine {
|
|
||||||
wineOnly = append(wineOnly, pat.cat)
|
|
||||||
cats = append(cats, pat.cat)
|
|
||||||
} else {
|
|
||||||
linOnly = append(linOnly, pat.cat)
|
|
||||||
cats = append(cats, pat.cat)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !pat.wine {
|
|
||||||
for i, v := range wineOnly {
|
|
||||||
if pat.cat == v {
|
|
||||||
wineOnly = append(wineOnly[:i], wineOnly[i+1:]...)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
appMaster[pat.cat] = append(appMaster[pat.cat], pat)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(linOnly)
|
|
||||||
sort.Strings(wineOnly)
|
|
||||||
sort.Strings(cats)
|
|
||||||
gl.StartDriver(uiMain)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func processApp(fi *os.File) (out prtap) {
|
func savePrefs() {
|
||||||
fis, _ := fi.Readdir(-1)
|
os.Remove("PortableApps/LinuxPACom/Prefs.gob")
|
||||||
if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
|
fil, err := os.Create("PortableApps/LinuxPACom/Prefs.gob")
|
||||||
out.name = getName(fil)
|
if err != nil {
|
||||||
fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
|
return
|
||||||
out.cat = getCat(fil)
|
|
||||||
} else if fil, err := os.Open(fi.Name() + "/appinfo.ini"); err == nil {
|
|
||||||
out.name = getName(fil)
|
|
||||||
fil, _ = os.Open(fi.Name() + "/appinfo.ini")
|
|
||||||
out.cat = getCat(fil)
|
|
||||||
} else {
|
|
||||||
out.cat = "Other"
|
|
||||||
}
|
}
|
||||||
if out.name == "" {
|
enc := gob.NewEncoder(fil)
|
||||||
out.name = path.Base(fi.Name())
|
err = enc.Encode(wine)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if out.cat == "" {
|
err = enc.Encode(portableHide)
|
||||||
out.cat = "Other"
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
//executable detection
|
err = enc.Encode(versionNewest)
|
||||||
wd, _ := os.Getwd()
|
if err != nil {
|
||||||
var rdr *bufio.Reader
|
return
|
||||||
for _, v := range fis {
|
|
||||||
fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
|
|
||||||
if err == nil {
|
|
||||||
stat, _ := fil.Stat()
|
|
||||||
if !stat.IsDir() {
|
|
||||||
rdr = bufio.NewReader(fil)
|
|
||||||
shebang := []byte{'#', '!'}
|
|
||||||
two := make([]byte, 2)
|
|
||||||
rdr.Read(two)
|
|
||||||
if reflect.DeepEqual(shebang, two) {
|
|
||||||
out.ex = wd + "/" + fi.Name() + "/" + v.Name()
|
|
||||||
rdr.Reset(fil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, v := range fis {
|
|
||||||
fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
|
|
||||||
if err == nil {
|
|
||||||
stat, _ := fil.Stat()
|
|
||||||
if !stat.IsDir() {
|
|
||||||
rdr = bufio.NewReader(fil)
|
|
||||||
thr := make([]byte, 4)
|
|
||||||
rdr.Read(thr)
|
|
||||||
if strings.Contains(string(thr), "ELF") {
|
|
||||||
out.ex = wd + "/" + fi.Name() + "/" + v.Name()
|
|
||||||
rdr.Reset(fil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, v := range fis {
|
|
||||||
fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
|
|
||||||
if err == nil {
|
|
||||||
stat, _ := fil.Stat()
|
|
||||||
if !stat.IsDir() && strings.HasSuffix(stat.Name(), "exe") {
|
|
||||||
out.wine = true
|
|
||||||
out.ex = wd + "/" + fi.Name() + "/" + v.Name()
|
|
||||||
out.name += " (Wine)"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prtap{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCat(fi *os.File) (out string) {
|
func loadPrefs() {
|
||||||
rdr := bufio.NewReader(fi)
|
fil, err := os.Open("PortableApps/LinuxPACom/Prefs.gob")
|
||||||
var err error
|
if err != nil {
|
||||||
var ln []byte
|
return
|
||||||
for err == nil {
|
}
|
||||||
ln, _, err = rdr.ReadLine()
|
dec := gob.NewDecoder(fil)
|
||||||
str := string(ln)
|
err = dec.Decode(&wine)
|
||||||
if strings.HasPrefix(str, "Category=") {
|
if err != nil {
|
||||||
out = strings.TrimPrefix(str, "Category=")
|
return
|
||||||
return
|
}
|
||||||
}
|
err = dec.Decode(&portableHide)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = dec.Decode(&versionNewest)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getName(fi *os.File) (out string) {
|
func contains(arr []string, str string) bool {
|
||||||
rdr := bufio.NewReader(fi)
|
for _, v := range arr {
|
||||||
var err error
|
if v == str {
|
||||||
var ln []byte
|
return true
|
||||||
for err == nil {
|
|
||||||
ln, _, err = rdr.ReadLine()
|
|
||||||
str := string(ln)
|
|
||||||
if strings.HasPrefix(str, "Name=") {
|
|
||||||
out = strings.TrimPrefix(str, "Name=")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
-130
@@ -1,130 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image"
|
|
||||||
"image/draw"
|
|
||||||
_ "image/png"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nelsam/gxui"
|
|
||||||
"github.com/nelsam/gxui/math"
|
|
||||||
)
|
|
||||||
|
|
||||||
type prtapAdap struct {
|
|
||||||
gxui.AdapterBase
|
|
||||||
wine bool
|
|
||||||
master []prtap
|
|
||||||
cur []prtap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) SetApps(apps []prtap) {
|
|
||||||
p.master = apps
|
|
||||||
if p.wine {
|
|
||||||
p.cur = p.master
|
|
||||||
} else {
|
|
||||||
p.cur = make([]prtap, 0)
|
|
||||||
for _, v := range p.master {
|
|
||||||
if !v.wine {
|
|
||||||
p.cur = append(p.cur, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.DataChanged(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Count() int {
|
|
||||||
return len(p.cur)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Wine(show bool) {
|
|
||||||
p.wine = show
|
|
||||||
if show {
|
|
||||||
p.cur = p.master
|
|
||||||
} else {
|
|
||||||
p.cur = make([]prtap, 0)
|
|
||||||
for _, v := range p.master {
|
|
||||||
if !v.wine {
|
|
||||||
p.cur = append(p.cur, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p.DataChanged(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Create(th gxui.Theme, index int) gxui.Control {
|
|
||||||
box := th.CreateLinearLayout()
|
|
||||||
box.SetPadding(math.CreateSpacing(2))
|
|
||||||
box.SetDirection(gxui.LeftToRight)
|
|
||||||
box.SetVerticalAlignment(gxui.AlignMiddle)
|
|
||||||
dir := path.Dir(p.cur[index].ex)
|
|
||||||
if fold, err := os.Open(dir + "/App/AppInfo"); err == nil {
|
|
||||||
var pics []string
|
|
||||||
fi, _ := fold.Readdirnames(-1)
|
|
||||||
for _, v := range fi {
|
|
||||||
if strings.HasPrefix(v, "appicon_") && strings.HasSuffix(v, ".png") {
|
|
||||||
pics = append(pics, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(pics) > 0 {
|
|
||||||
ind := sort.SearchStrings(pics, "appicon_128.png")
|
|
||||||
if ind == len(pics) {
|
|
||||||
ind = len(pics) - 1
|
|
||||||
}
|
|
||||||
imgfi, _ := os.Open(dir + "/App/AppInfo/" + pics[ind])
|
|
||||||
img, _, err := image.Decode(imgfi)
|
|
||||||
if err == nil {
|
|
||||||
rgba := image.NewRGBA(img.Bounds())
|
|
||||||
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
|
||||||
tex := dr.CreateTexture(rgba, 1)
|
|
||||||
icon := th.CreateImage()
|
|
||||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
|
||||||
icon.SetTexture(tex)
|
|
||||||
box.AddChild(icon)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if fi, err := os.Open(dir + "/appicon.png"); err == nil {
|
|
||||||
img, _, err := image.Decode(fi)
|
|
||||||
if err == nil {
|
|
||||||
rgba := image.NewRGBA(img.Bounds())
|
|
||||||
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
|
|
||||||
tex := dr.CreateTexture(rgba, 1)
|
|
||||||
icon := th.CreateImage()
|
|
||||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
|
||||||
icon.SetTexture(tex)
|
|
||||||
box.AddChild(icon)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//Creating empty Image so that names line up
|
|
||||||
icon := th.CreateImage()
|
|
||||||
icon.SetExplicitSize(math.Size{H: 32, W: 32})
|
|
||||||
box.AddChild(icon)
|
|
||||||
}
|
|
||||||
lbl := th.CreateLabel()
|
|
||||||
lbl.SetText(p.cur[index].name)
|
|
||||||
box.AddChild(lbl)
|
|
||||||
return box
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) ItemAt(index int) gxui.AdapterItem {
|
|
||||||
return p.cur[index]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int {
|
|
||||||
it, ok := item.(prtap)
|
|
||||||
if !ok {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
for i, v := range p.cur {
|
|
||||||
if v == it {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *prtapAdap) Size(gxui.Theme) math.Size {
|
|
||||||
return math.Size{W: math.MaxSize.W, H: 36}
|
|
||||||
}
|
|
||||||
+159
@@ -0,0 +1,159 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/glib"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func settingsUI(parent *gtk.Window, onExit func()) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
win.SetDefaultSize(600, 300)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
onExit()
|
||||||
|
})
|
||||||
|
comTagTbl, _ := gtk.TextTagTableNew()
|
||||||
|
comBuf, _ := gtk.TextBufferNew(comTagTbl)
|
||||||
|
ntbk, _ := gtk.NotebookNew()
|
||||||
|
gnrl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
gnrl.SetMarginStart(10)
|
||||||
|
gnrl.SetMarginEnd(10)
|
||||||
|
gnrl.SetMarginTop(10)
|
||||||
|
gnrl.SetMarginBottom(10)
|
||||||
|
dlWine, _ := gtk.ButtonNewWithLabel("Download Wine")
|
||||||
|
wineCheck, _ := gtk.CheckButtonNewWithLabel("Show Windows apps (Wine)")
|
||||||
|
wineLbl, _ := gtk.LabelNew("PortableApps/LinuxPACom/Wine present")
|
||||||
|
dlWine.Connect("clicked", func() {
|
||||||
|
cb := make(chan bool)
|
||||||
|
downloadWine(win, cb)
|
||||||
|
go func() {
|
||||||
|
v := <-cb
|
||||||
|
if v {
|
||||||
|
setupTxt(comBuf)
|
||||||
|
wineLbl.Show()
|
||||||
|
}
|
||||||
|
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); os.IsNotExist(err) {
|
||||||
|
if _, errd := exec.LookPath("wine"); errd == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
glib.IdleAdd(func() {
|
||||||
|
if !wineAvail {
|
||||||
|
wineCheck.SetSensitive(false)
|
||||||
|
wineCheck.SetTooltipText("Download wine to run windows apps")
|
||||||
|
} else {
|
||||||
|
wineCheck.SetSensitive(true)
|
||||||
|
wineCheck.SetTooltipText("")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
if !comEnbld {
|
||||||
|
dlWine.SetSensitive(false)
|
||||||
|
dlWine.SetTooltipText("common.sh needed")
|
||||||
|
}
|
||||||
|
pthdCheck, _ := gtk.CheckButtonNewWithLabel("Hide \"Portable\" from app name")
|
||||||
|
pthdCheck.Connect("toggled", func() {
|
||||||
|
portableHide = pthdCheck.GetActive()
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
cats = make([]string, 0)
|
||||||
|
lin = make([]string, 0)
|
||||||
|
setup()
|
||||||
|
})
|
||||||
|
pthdCheck.SetActive(portableHide)
|
||||||
|
if !wineAvail {
|
||||||
|
wineCheck.SetSensitive(false)
|
||||||
|
wineCheck.SetTooltipText("Download wine to run windows apps")
|
||||||
|
}
|
||||||
|
wineCheck.SetActive(wine)
|
||||||
|
wineCheck.Connect("toggled", func() {
|
||||||
|
wine = wineCheck.GetActive()
|
||||||
|
})
|
||||||
|
versCheck, _ := gtk.CheckButtonNewWithLabel("Only show newest app version in downloads (A bit iffy ATM)")
|
||||||
|
versCheck.SetActive(versionNewest)
|
||||||
|
versCheck.Connect("toggled", func() {
|
||||||
|
versionNewest = versCheck.GetActive()
|
||||||
|
})
|
||||||
|
gnrl.Add(wineLbl)
|
||||||
|
gnrl.Add(dlWine)
|
||||||
|
gnrl.Add(pthdCheck)
|
||||||
|
gnrl.Add(wineCheck)
|
||||||
|
gnrl.Add(versCheck)
|
||||||
|
ntbk.AppendPage(gnrl, getLabel("General"))
|
||||||
|
com, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
com.SetMarginStart(10)
|
||||||
|
com.SetMarginEnd(10)
|
||||||
|
com.SetMarginTop(10)
|
||||||
|
com.SetMarginBottom(10)
|
||||||
|
comEdit, _ := gtk.TextViewNewWithBuffer(comBuf)
|
||||||
|
comEdit.SetVExpand(true)
|
||||||
|
comEdit.SetHExpand(true)
|
||||||
|
vScroll, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
hScroll, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
|
comScrl, _ := gtk.ScrolledWindowNew(hScroll, vScroll)
|
||||||
|
comScrl.Add(comEdit)
|
||||||
|
svBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
|
sv, _ := gtk.ButtonNewWithLabel("Save")
|
||||||
|
sv.Connect("clicked", func() {
|
||||||
|
beg, end := comBuf.GetBounds()
|
||||||
|
txt, _ := comBuf.GetText(beg, end, true)
|
||||||
|
ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", []byte(txt), 0777)
|
||||||
|
})
|
||||||
|
cnl, _ := gtk.ButtonNewWithLabel("Cancel")
|
||||||
|
cnl.Connect("clicked", func() {
|
||||||
|
setupTxt(comBuf)
|
||||||
|
})
|
||||||
|
svBox.Add(sv)
|
||||||
|
svBox.Add(cnl)
|
||||||
|
com.Add(comScrl)
|
||||||
|
com.Add(svBox)
|
||||||
|
ntbk.AppendPage(com, getLabel("common.sh"))
|
||||||
|
win.Add(ntbk)
|
||||||
|
win.ShowAll()
|
||||||
|
if !comEnbld {
|
||||||
|
comScrl.Hide()
|
||||||
|
svBox.Hide()
|
||||||
|
mkCom, _ := gtk.ButtonNewWithLabel("Create common.sh")
|
||||||
|
mkCom.Connect("clicked", func() {
|
||||||
|
err := ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", []byte("export HOME=$PWD/PortableApps/LinuxPACom/Home"), 0777)
|
||||||
|
if err == nil {
|
||||||
|
mkCom.Hide()
|
||||||
|
comScrl.Show()
|
||||||
|
svBox.Show()
|
||||||
|
setupTxt(comBuf)
|
||||||
|
comEnbld = true
|
||||||
|
dlWine.SetSensitive(true)
|
||||||
|
dlWine.SetTooltipText("")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
mkCom.Show()
|
||||||
|
com.Add(mkCom)
|
||||||
|
} else {
|
||||||
|
setupTxt(comBuf)
|
||||||
|
}
|
||||||
|
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); err != nil && os.IsNotExist(err) {
|
||||||
|
wineLbl.Hide()
|
||||||
|
}
|
||||||
|
win.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTxt(buf *gtk.TextBuffer) {
|
||||||
|
fil, _ := os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
btys, _ := ioutil.ReadAll(fil)
|
||||||
|
buf.SetText(string(btys))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLabel(name string) *gtk.Label {
|
||||||
|
lbl, _ := gtk.LabelNew(name)
|
||||||
|
return lbl
|
||||||
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
_ "image/png"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gdk"
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setup() {
|
||||||
|
loadPrefs()
|
||||||
|
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); os.IsNotExist(err) {
|
||||||
|
if _, errd := exec.LookPath("wine"); errd == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
} else if err == nil {
|
||||||
|
wineAvail = true
|
||||||
|
}
|
||||||
|
if !wineAvail {
|
||||||
|
wine = false
|
||||||
|
}
|
||||||
|
PortableAppsFold, err := os.Open("PortableApps")
|
||||||
|
if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() {
|
||||||
|
os.Mkdir("PortableApps", 0777)
|
||||||
|
PortableAppsFold, err = os.Open("PortableApps")
|
||||||
|
if err != nil {
|
||||||
|
panic("Can't find PortableApps folder and can't create one!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err = os.Open("PortableApps/LinuxPACom"); err != nil {
|
||||||
|
os.Mkdir("PortableApps/LinuxPACom", 0777)
|
||||||
|
}
|
||||||
|
_, err = os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
if err == nil {
|
||||||
|
comEnbld = true
|
||||||
|
}
|
||||||
|
PAFolds, _ := PortableAppsFold.Readdirnames(-1)
|
||||||
|
sort.Strings(PAFolds)
|
||||||
|
for _, v := range PAFolds {
|
||||||
|
fold, _ := os.Open("PortableApps/" + v)
|
||||||
|
if stat, _ := fold.Stat(); stat.IsDir() && stat.Name() != "PortableApps.com" && stat.Name() != "LinuxPACom" {
|
||||||
|
ap := processApp("PortableApps/" + v)
|
||||||
|
if !reflect.DeepEqual(ap, app{}) {
|
||||||
|
if _, ok := master[ap.cat]; !ok {
|
||||||
|
cats = append(cats, ap.cat)
|
||||||
|
sort.Strings(cats)
|
||||||
|
}
|
||||||
|
if len(ap.lin) != 0 {
|
||||||
|
if _, ok := linmaster[ap.cat]; !ok {
|
||||||
|
lin = append(lin, ap.cat)
|
||||||
|
sort.Strings(lin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
master[ap.cat] = append(master[ap.cat], ap)
|
||||||
|
if len(ap.lin) != 0 {
|
||||||
|
linmaster[ap.cat] = append(linmaster[ap.cat], ap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func processApp(fold string) (out app) {
|
||||||
|
wd, _ := os.Getwd()
|
||||||
|
out.dir = wd + "/" + fold
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
if out.ini != nil {
|
||||||
|
out.name = getName(out.ini)
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
out.cat = getCat(out.ini)
|
||||||
|
out.ini = findInfo(fold)
|
||||||
|
}
|
||||||
|
if out.name == "" {
|
||||||
|
out.name = strings.TrimPrefix(fold, "PortableApps/")
|
||||||
|
}
|
||||||
|
if out.cat == "" {
|
||||||
|
out.cat = "Other"
|
||||||
|
}
|
||||||
|
if portableHide {
|
||||||
|
out.name = strings.TrimSuffix(out.name, "Portable")
|
||||||
|
}
|
||||||
|
out.icon = getIcon(fold)
|
||||||
|
folder, _ := os.Open(fold)
|
||||||
|
fis, _ := folder.Readdirnames(-1)
|
||||||
|
for _, v := range fis {
|
||||||
|
tmp, _ := os.Open(fold + "/" + v)
|
||||||
|
if stat, _ := tmp.Stat(); stat.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(strings.ToLower(v), ".appimage") {
|
||||||
|
out.appimg = append(out.appimg, v)
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
out.lin = append(out.lin, v)
|
||||||
|
} else if strings.HasSuffix(strings.ToLower(v), ".exe") {
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
} else {
|
||||||
|
btys := make([]byte, 4)
|
||||||
|
rdr := bufio.NewReader(tmp)
|
||||||
|
rdr.Read(btys)
|
||||||
|
if (strings.Contains(strings.ToLower(string(btys)), "elf") && !strings.HasSuffix(strings.ToLower(v), ".so") && !strings.Contains(v, ".so.")) || strings.HasPrefix(strings.ToLower(string(btys)), "#!") {
|
||||||
|
out.ex = append(out.ex, v)
|
||||||
|
out.lin = append(out.lin, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(out.ex) == 0 {
|
||||||
|
return app{}
|
||||||
|
}
|
||||||
|
if len(out.lin) == 0 {
|
||||||
|
out.name += " (Wine)"
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCat(ini *os.File) string {
|
||||||
|
rdr := bufio.NewReader(ini)
|
||||||
|
var ret string
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
if strings.HasPrefix(string(line), "Category=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "Category=")
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(string(line), "category=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "category=")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdr.Reset(ini)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getName(ini *os.File) string {
|
||||||
|
rdr := bufio.NewReader(ini)
|
||||||
|
var ret string
|
||||||
|
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
|
||||||
|
if strings.HasPrefix(string(line), "Name=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "Name=")
|
||||||
|
break
|
||||||
|
} else if strings.HasPrefix(string(line), "name=") {
|
||||||
|
ret = strings.TrimPrefix(string(line), "name=")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rdr.Reset(ini)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func getIcon(fold string) *gdk.Pixbuf {
|
||||||
|
var pic string
|
||||||
|
if _, err := os.Open(fold + "/appicon.png"); err == nil {
|
||||||
|
pic = fold + "/appicon.png"
|
||||||
|
} else if folder, err := os.Open(fold + "/App/AppInfo"); err == nil {
|
||||||
|
fis, _ := folder.Readdir(-1)
|
||||||
|
var pics []string
|
||||||
|
for _, v := range fis {
|
||||||
|
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".png") && strings.HasPrefix(strings.ToLower(v.Name()), "appicon_") {
|
||||||
|
pics = append(pics, v.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(pics)
|
||||||
|
if len(pics) > 1 {
|
||||||
|
var ind int
|
||||||
|
if !contains(pics, "appicon_32.png") {
|
||||||
|
ind = len(pics) - 1
|
||||||
|
} else {
|
||||||
|
ind = sort.SearchStrings(pics, "appicon_32.png")
|
||||||
|
}
|
||||||
|
pic = fold + "/App/AppInfo/" + pics[ind]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
img, _ := gtk.ImageNewFromIconName("application-x-executable", gtk.ICON_SIZE_BUTTON)
|
||||||
|
buf := img.GetPixbuf()
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
img, _ := gtk.ImageNewFromFile(pic)
|
||||||
|
buf, _ := img.GetPixbuf().ScaleSimple(32, 32, gdk.INTERP_BILINEAR)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func findInfo(fold string) *os.File {
|
||||||
|
if fi, err := os.Open(fold + "/appinfo.ini"); err == nil {
|
||||||
|
return fi
|
||||||
|
}
|
||||||
|
tmp, err := os.Open(fold + "/App/AppInfo")
|
||||||
|
if err == nil {
|
||||||
|
fis, _ := tmp.Readdirnames(-1)
|
||||||
|
for _, v := range fis {
|
||||||
|
if strings.ToLower(v) == "appinfo.ini" {
|
||||||
|
tmp, _ := os.Open(fold + "/App/AppInfo/" + v)
|
||||||
|
return tmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,90 +1,188 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/CalebQ42/LinuxPA/appimg"
|
||||||
"os"
|
"github.com/gotk3/gotk3/glib"
|
||||||
"os/exec"
|
"github.com/gotk3/gotk3/gtk"
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/nelsam/gxui"
|
|
||||||
"github.com/nelsam/gxui/themes/dark"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func ui(win *gtk.Window) {
|
||||||
dr gxui.Driver
|
ls := getCatRows()
|
||||||
)
|
var treeApps []*gtk.TreeIter
|
||||||
|
header, _ := gtk.HeaderBarNew()
|
||||||
func uiMain(dri gxui.Driver) {
|
header.SetShowCloseButton(true)
|
||||||
dr = dri
|
header.SetTitle("LinuxPA")
|
||||||
catAdap := &StrList{}
|
header.SetSubtitle("PortableApps.com type launcher")
|
||||||
catAdap.SetStrings(linOnly)
|
settings, _ := gtk.ButtonNewFromIconName("applications-system", gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||||
appAdap := &prtapAdap{}
|
settings.SetTooltipText("Settings")
|
||||||
appAdap.Wine(false)
|
dnl, _ := gtk.ButtonNewFromIconName("emblem-downloads", gtk.ICON_SIZE_SMALL_TOOLBAR)
|
||||||
th := dark.CreateTheme(dr)
|
dnl.SetTooltipText("Download Apps")
|
||||||
win := th.CreateWindow(500, 500, "LinuxPA")
|
header.PackStart(settings)
|
||||||
top := th.CreateLinearLayout()
|
header.PackEnd(dnl)
|
||||||
top.SetDirection(gxui.BottomToTop)
|
win.SetTitlebar(header)
|
||||||
top.SetHorizontalAlignment(gxui.AlignRight)
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
|
||||||
spl := th.CreateSplitterLayout()
|
lrBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
|
||||||
spl.SetOrientation(gxui.Horizontal)
|
catList, _ := gtk.ListBoxNew()
|
||||||
catlist := th.CreateList()
|
catList.SetActivateOnSingleClick(true)
|
||||||
catlist.SetAdapter(catAdap)
|
store, _ := gtk.TreeStoreNew(glib.TYPE_OBJECT, glib.TYPE_STRING)
|
||||||
catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
|
appsList, _ := gtk.TreeViewNewWithModel(store)
|
||||||
str := it.(string)
|
render, _ := gtk.CellRendererPixbufNew()
|
||||||
appAdap.SetApps(appMaster[str])
|
pixColumn, _ := gtk.TreeViewColumnNewWithAttribute("", render, "pixbuf", 0)
|
||||||
})
|
txtRender, _ := gtk.CellRendererTextNew()
|
||||||
applist := th.CreateList()
|
txtColumn, _ := gtk.TreeViewColumnNewWithAttribute("", txtRender, "text", 1)
|
||||||
applist.SetAdapter(appAdap)
|
appsList.AppendColumn(pixColumn)
|
||||||
spl.AddChild(catlist)
|
appsList.AppendColumn(txtColumn)
|
||||||
spl.AddChild(applist)
|
appsList.SetHeadersVisible(false)
|
||||||
but := th.CreateLinearLayout()
|
catList.SetHExpand(true)
|
||||||
but.SetDirection(gxui.RightToLeft)
|
catList.SetVExpand(true)
|
||||||
launch := th.CreateButton()
|
appsList.SetHExpand(true)
|
||||||
launch.SetText("Launch!")
|
appsList.SetVExpand(true)
|
||||||
launch.OnClick(func(gxui.MouseEvent) {
|
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
if appAdap.ItemIndex(applist.Selected()) != -1 {
|
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
app := applist.Selected().(prtap)
|
vScrollApp, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
dir, fi := path.Split(app.ex)
|
hScrollApp, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
|
||||||
var cmd *exec.Cmd
|
catScrl, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
|
||||||
if app.wine {
|
catScrl.Add(catList)
|
||||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; wine \""+fi+"\"")
|
catScrl.SetSizeRequest(170, 500)
|
||||||
|
appScrl, _ := gtk.ScrolledWindowNew(hScrollApp, vScrollApp)
|
||||||
|
appScrl.Add(appsList)
|
||||||
|
appScrl.SetSizeRequest(300, 500)
|
||||||
|
lrBox.Add(catScrl)
|
||||||
|
lrBox.Add(appScrl)
|
||||||
|
botBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 2)
|
||||||
|
botBox.SetMarginStart(10)
|
||||||
|
botBox.SetMarginEnd(10)
|
||||||
|
botBox.SetMarginTop(10)
|
||||||
|
botBox.SetMarginBottom(10)
|
||||||
|
edit, _ := gtk.ButtonNewWithLabel("Edit App..")
|
||||||
|
edit.Connect("clicked", func() {
|
||||||
|
selec, _ := appsList.GetSelection()
|
||||||
|
_, it, ok := selec.GetSelected()
|
||||||
|
if ok {
|
||||||
|
pth, _ := store.GetPath(it)
|
||||||
|
ind := pth.GetIndices()
|
||||||
|
if wine {
|
||||||
|
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.edit(win, func() {
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
if commEnbl {
|
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
|
appLnch.edit(win, func() {
|
||||||
} else {
|
store.Clear()
|
||||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
|
for i := range ls {
|
||||||
}
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
cmd.Stdin = os.Stdin
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
cmd.Start()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if _, err := exec.LookPath("wine"); err == nil {
|
botBox.PackEnd(edit, false, false, 0)
|
||||||
fmt.Println("Wine found!")
|
topLvl.Add(lrBox)
|
||||||
wine := th.CreateButton()
|
topLvl.PackEnd(botBox, false, true, 0)
|
||||||
wine.SetType(gxui.ToggleButton)
|
win.Add(topLvl)
|
||||||
wine.OnClick(func(gxui.MouseEvent) {
|
for _, v := range ls {
|
||||||
if wine.IsChecked() {
|
catList.Add(v)
|
||||||
catAdap.SetStrings(cats)
|
|
||||||
appAdap.Wine(true)
|
|
||||||
} else {
|
|
||||||
catAdap.SetStrings(linOnly)
|
|
||||||
appAdap.Wine(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
wine.SetText("Show Windows Apps")
|
|
||||||
wine.SetChecked(appAdap.wine)
|
|
||||||
but.AddChild(wine)
|
|
||||||
} else {
|
|
||||||
fmt.Println("Wine not found!")
|
|
||||||
}
|
}
|
||||||
but.AddChild(launch)
|
catList.Connect("row-selected", func() {
|
||||||
top.AddChild(but)
|
store.Clear()
|
||||||
top.AddChild(spl)
|
if catList.GetSelectedRow().GetIndex() >= 0 {
|
||||||
win.AddChild(top)
|
treeApps = make([]*gtk.TreeIter, 0)
|
||||||
win.OnClose(func() {
|
if wine {
|
||||||
dr.Terminate()
|
apps := master[cats[catList.GetSelectedRow().GetIndex()]]
|
||||||
|
for _, v := range apps {
|
||||||
|
treeApps = append(treeApps, v.getTreeIter(store))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
apps := linmaster[lin[catList.GetSelectedRow().GetIndex()]]
|
||||||
|
for _, v := range apps {
|
||||||
|
treeApps = append(treeApps, v.getTreeIter(store))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
appsList.Connect("row-activated", func() {
|
||||||
|
selec, _ := appsList.GetSelection()
|
||||||
|
_, it, ok := selec.GetSelected()
|
||||||
|
if ok {
|
||||||
|
pth, _ := store.GetPath(it)
|
||||||
|
ind := pth.GetIndices()
|
||||||
|
if len(ind) == 1 {
|
||||||
|
if wine {
|
||||||
|
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launch()
|
||||||
|
} else {
|
||||||
|
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launch()
|
||||||
|
}
|
||||||
|
} else if len(ind) == 2 {
|
||||||
|
if wine {
|
||||||
|
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launchSub(ind[1])
|
||||||
|
} else {
|
||||||
|
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||||
|
appLnch.launchSub(ind[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dnl.Connect("clicked", func() {
|
||||||
|
appimg.ShowUI(versionNewest, func() {
|
||||||
|
master = make(map[string][]app)
|
||||||
|
linmaster = make(map[string][]app)
|
||||||
|
cats = make([]string, 0)
|
||||||
|
lin = make([]string, 0)
|
||||||
|
setup()
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
settings.Connect("clicked", func() {
|
||||||
|
settingsUI(win, func() {
|
||||||
|
store.Clear()
|
||||||
|
for i := range ls {
|
||||||
|
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||||
|
}
|
||||||
|
ls = getCatRows()
|
||||||
|
for i, v := range ls {
|
||||||
|
catList.Insert(v, i)
|
||||||
|
}
|
||||||
|
catList.ShowAll()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCatRows() (out []*gtk.Label) {
|
||||||
|
if wine {
|
||||||
|
for _, v := range cats {
|
||||||
|
txt, _ := gtk.LabelNew(v)
|
||||||
|
out = append(out, txt)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range lin {
|
||||||
|
txt, _ := gtk.LabelNew(v)
|
||||||
|
out = append(out, txt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
versionURL = "https://www.dropbox.com/s/a0xizzo0a4vsfqt/Version?dl=1"
|
||||||
|
downloadURL = "https://github.com/CalebQ42/LinuxPA/releases/download/vXXX/LinuxPA"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Thanks to https://www.socketloop.com/tutorials/golang-download-file-example
|
||||||
|
//For some of the code
|
||||||
|
|
||||||
|
//Returns if success
|
||||||
|
func versionDL() (bool, error) {
|
||||||
|
versionFile, err := os.Create("PortableApps/LinuxPACom/Version")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
versionFile.Chmod(0777)
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response, err := check.Get(versionURL)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(versionFile, response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVersionFileInfo() string {
|
||||||
|
fil, err := os.Open("PortableApps/LinuxPACom/Version")
|
||||||
|
if err != nil {
|
||||||
|
return "Error!"
|
||||||
|
}
|
||||||
|
rdr := bufio.NewReader(fil)
|
||||||
|
out, _, _ := rdr.ReadLine()
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkForUpdate(new string) (bool, error) {
|
||||||
|
curSlice := strings.Split(version, ".")
|
||||||
|
newSlice := strings.Split(new, ".")
|
||||||
|
curNums := make([]int, 4)
|
||||||
|
newNums := make([]int, 4)
|
||||||
|
for i, v := range curSlice {
|
||||||
|
num, err := strconv.Atoi(v)
|
||||||
|
if err == nil {
|
||||||
|
curNums[i] = num
|
||||||
|
}
|
||||||
|
num, err = strconv.Atoi(newSlice[i])
|
||||||
|
if err == nil {
|
||||||
|
newNums[i] = num
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if newNums[i] > curNums[i] {
|
||||||
|
return true, nil
|
||||||
|
} else if curNums[i] > newNums[i] {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadUpdate(newVersion string) (bool, error) {
|
||||||
|
url := strings.Replace(downloadURL, "XXX", newVersion, -1)
|
||||||
|
err := os.Rename("LinuxPA", ".LinuxPA.old")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
fil, err := os.Create("LinuxPA")
|
||||||
|
fil.Chmod(0777)
|
||||||
|
defer fil.Close()
|
||||||
|
if err != nil {
|
||||||
|
os.Rename(".LinuxPA.old", "LinuxPA")
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
re, err := check.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
defer re.Body.Close()
|
||||||
|
_, err = io.Copy(fil, re.Body)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(win *gtk.Window) {
|
||||||
|
updateWin, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
|
||||||
|
updateWin.SetTransientFor(win)
|
||||||
|
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
spin, _ := gtk.SpinnerNew()
|
||||||
|
spin.Start()
|
||||||
|
lbl, _ := gtk.LabelNew("Checking for updates")
|
||||||
|
topLvl.Add(spin)
|
||||||
|
topLvl.Add(lbl)
|
||||||
|
topLvl.SetMarginBottom(10)
|
||||||
|
topLvl.SetMarginEnd(10)
|
||||||
|
topLvl.SetMarginStart(10)
|
||||||
|
topLvl.SetMarginTop(10)
|
||||||
|
updateWin.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
updateWin.Add(topLvl)
|
||||||
|
updateWin.ShowAll()
|
||||||
|
updateWin.Show()
|
||||||
|
go func(win, updateWin *gtk.Window) {
|
||||||
|
defer updateWin.Close()
|
||||||
|
stat, err := versionDL()
|
||||||
|
if stat {
|
||||||
|
res := getVersionFileInfo()
|
||||||
|
if res != "Error!" {
|
||||||
|
stat, err = checkForUpdate(res)
|
||||||
|
if stat {
|
||||||
|
lbl.SetText("Updating!")
|
||||||
|
downloadUpdate(res)
|
||||||
|
win.Close()
|
||||||
|
cmd := exec.Command("./LinuxPA")
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Start()
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Failed Version File Info")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}(win, updateWin)
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gotk3/gotk3/gtk"
|
||||||
|
"github.com/mholt/archiver"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
wineURL = "https://www.playonlinux.com/wine/binaries/linux-amd64/PlayOnLinux-wine-2.5-linux-amd64.pol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func downloadWine(parent *gtk.Window, cb chan bool) {
|
||||||
|
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||||
|
win.SetTransientFor(parent)
|
||||||
|
win.SetDestroyWithParent(true)
|
||||||
|
win.Connect("destroy", func() {
|
||||||
|
parent.SetSensitive(true)
|
||||||
|
})
|
||||||
|
parent.SetSensitive(false)
|
||||||
|
spin, _ := gtk.SpinnerNew()
|
||||||
|
spin.Start()
|
||||||
|
txt, _ := gtk.LabelNew("Downloading Wine")
|
||||||
|
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
|
||||||
|
box.SetMarginBottom(10)
|
||||||
|
box.SetMarginEnd(10)
|
||||||
|
box.SetMarginStart(10)
|
||||||
|
box.SetMarginTop(10)
|
||||||
|
box.Add(spin)
|
||||||
|
box.Add(txt)
|
||||||
|
win.Add(box)
|
||||||
|
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
|
||||||
|
win.ShowAll()
|
||||||
|
win.Show()
|
||||||
|
go func(win *gtk.Window, txt *gtk.Label) {
|
||||||
|
defer win.Close()
|
||||||
|
wineTar, err := os.Create("PortableApps/LinuxPACom/wine2.5.tar.bz2")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer wineTar.Close()
|
||||||
|
check := http.Client{
|
||||||
|
CheckRedirect: func(r *http.Request, via []*http.Request) error {
|
||||||
|
r.URL.Opaque = r.URL.Path
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp, err := check.Get(wineURL)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.RemoveAll("PortableApps/LinuxPACom/Wine")
|
||||||
|
defer resp.Body.Close()
|
||||||
|
_, err = io.Copy(wineTar, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
txt.SetText("Extracting Wine")
|
||||||
|
err = archiver.TarBz2.Open("PortableApps/LinuxPACom/wine2.5.tar.bz2", "PortableApps/LinuxPACom/Wine")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fil, err := os.Open("PortableApps/LinuxPACom/common.sh")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tmp, err := ioutil.ReadAll(fil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(tmp), "export PATH=$PWD/PortableApps/LinuxPACom/Wine/wineversion/2.5/bin:$PATH") {
|
||||||
|
tmp = append(tmp, []byte("\nexport PATH=$PWD/PortableApps/LinuxPACom/Wine/wineversion/2.5/bin:$PATH")...)
|
||||||
|
ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", tmp, 0777)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
cb <- false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb <- true
|
||||||
|
return
|
||||||
|
}(win, txt)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user