12 Commits

Author SHA1 Message Date
Belac Darkstorm fc3411e568 Added Button to launch PortableApps.com launcher. Added back common.sh support (oops) 2016-09-22 08:39:56 -05:00
Belac Darkstorm 77ce9e8ad4 appinfo.ini detection no longer capitalization dependent 2016-09-22 00:25:58 -05:00
Belac Darkstorm 63dd8ebb83 Added a bit better appinfo.ini detection 2016-09-22 00:21:00 -05:00
Belac Darkstorm 7cf45c9ac8 Allow for multiple executables. Double click to launch instead of the launch button 2016-09-22 00:11:32 -05:00
Belac Darkstorm 2f8de0bed2 fix with wine 2016-09-14 09:30:06 -05:00
Belac Darkstorm 67ca030bb2 Updated README 2016-09-14 08:05:18 -05:00
Belac Darkstorm da46399ded Wine support work continued 2016-09-14 03:18:09 -05:00
Belac Darkstorm e5d0b6a9a2 First rendition of wine support (needs some work still) 2016-09-14 02:31:04 -05:00
Belac Darkstorm f4ca2115d4 Stderr output 2016-09-14 02:06:56 -05:00
Belac Darkstorm 0cc7f8f445 Updated README 2016-09-13 08:27:05 -05:00
Belac Darkstorm 767e894acd Updated README 2016-09-13 08:25:52 -05:00
Belac Darkstorm 06e2afef1d Updated README 2016-09-13 08:03:55 -05:00
7 changed files with 508 additions and 287 deletions
+7 -7
View File
@@ -1,21 +1,21 @@
# LinuxPA
LinuxPA is a try to bring a PortableApps.com type launcher to Linux.
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
# App Detection
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.
# How to use
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, but if one isn't found it launches the first executable in general.
# PortableApps.com Compatability
# 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.
# 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).
# Simple App Setup
Because apps aren't natively formated in the PortableApps.com format, if LinuxPA doesn't find the AppInfo.ini or appicon_\*.png in the App/AppInfo folder of the app it looks for them in the root direcory of the app (except it looks, nor for appicon_\*.png, but appicon.png)
Because apps aren't natively formated in the PortableApps.com format, if LinuxPA doesn't find the AppInfo.ini or appicon_\*.png in the App/AppInfo folder of the app it looks for them in the root directory of the app (except it looks, nor for appicon_\*.png, but appicon.png). If an AppInfo.ini file isn't found then the name of the app is grabbed from the folder name and it's category is set to other. It specifically looks for the lines starting with `Name=` and `Category=`
# AppImage Support
[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 downloading 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
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`
@@ -25,8 +25,8 @@ Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
# TODO (Might be in order)
1. MAKE IT BETTER
1. Launching of .exe files via wine (wine will have to be installed on the host system, unless there is some portable wine (I may have found one))
1. Add settings menu
1. Add updater for .AppImage files
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. Portable wine???
+259
View File
@@ -0,0 +1,259 @@
package main
import (
"os"
"os/exec"
"sort"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/math"
)
type app struct {
name string
cat string
appimg []string
lin []string
ex []string
icon gxui.Texture
dir string
ini *os.File
}
type appExNode struct {
ap app
exInd int
}
func (a *appExNode) launch() {
if wine {
var cmd *exec.Cmd
if ind := sort.SearchStrings(a.ap.lin, a.ap.ex[a.exInd]); ind == len(a.ap.lin) {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[a.exInd]+"\"")
} else {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
}
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
var cmd *exec.Cmd
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
func (a *appExNode) Count() int {
return 0
}
func (a *appExNode) NodeAt(int) gxui.TreeNode {
return nil
}
func (a *appExNode) ItemIndex(gxui.AdapterItem) int {
return -1
}
func (a *appExNode) Item() gxui.AdapterItem {
if wine {
return a.ap.ex[a.exInd]
}
return a.ap.lin[a.exInd]
}
func (a *appExNode) Create(the gxui.Theme) gxui.Control {
box := the.CreateLinearLayout()
box.SetDirection(gxui.LeftToRight)
box.SetVerticalAlignment(gxui.AlignMiddle)
img := the.CreateImage()
img.SetTexture(a.ap.icon)
img.SetExplicitSize(math.Size{H: 32, W: 32})
lbl := the.CreateLabel()
lbl.SetText(a.ap.ex[a.exInd])
box.AddChild(img)
box.AddChild(lbl)
box.OnDoubleClick(func(gxui.MouseEvent) {
a.launch()
})
return box
}
type appNode struct {
ap app
}
func (a *appNode) launch() {
if len(a.ap.ex) == 1 {
if wine {
var cmd *exec.Cmd
if ind := sort.SearchStrings(a.ap.lin, a.ap.ex[0]); ind == len(a.ap.lin) {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
} else {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.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.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
} else {
if wine {
var cmd *exec.Cmd
if len(a.ap.lin) == 0 {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
} else {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
}
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
} else {
if len(a.ap.lin) != 0 {
var cmd *exec.Cmd
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[0]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
}
}
}
func (a *appNode) Count() int {
if wine {
if len(a.ap.ex) > 1 {
return len(a.ap.ex)
}
return 0
}
if len(a.ap.lin) > 1 {
return len(a.ap.lin)
}
return 0
}
func (a *appNode) NodeAt(i int) gxui.TreeNode {
return &appExNode{ap: a.ap, exInd: i}
}
func (a *appNode) ItemIndex(item gxui.AdapterItem) int {
if wine {
for i, v := range a.ap.ex {
if v == item {
return i
}
}
} else {
for i, v := range a.ap.lin {
if v == item {
return i
}
}
}
return -1
}
func (a *appNode) Item() gxui.AdapterItem {
return a.ap.name
}
func (a *appNode) Create(the gxui.Theme) gxui.Control {
box := the.CreateLinearLayout()
box.SetDirection(gxui.LeftToRight)
box.SetPadding(math.CreateSpacing(2))
box.SetVerticalAlignment(gxui.AlignMiddle)
img := the.CreateImage()
if a.ap.icon != nil {
img.SetTexture(a.ap.icon)
}
img.SetExplicitSize(math.Size{H: 32, W: 32})
lbl := the.CreateLabel()
lbl.SetText(a.ap.name)
box.AddChild(img)
box.AddChild(lbl)
box.OnDoubleClick(func(gxui.MouseEvent) {
a.launch()
})
return box
}
type catAdap struct {
gxui.AdapterBase
cat string
}
func (a *catAdap) setCat(cat string) {
a.cat = cat
a.DataChanged(false)
}
func (a *catAdap) refresh() {
a.DataChanged(false)
}
func (a *catAdap) Count() int {
if wine {
return len(master[a.cat])
}
return len(linmaster[a.cat])
}
func (a *catAdap) NodeAt(i int) gxui.TreeNode {
if wine {
return &appNode{ap: master[a.cat][i]}
}
return &appNode{ap: linmaster[a.cat][i]}
}
func (a *catAdap) Size(gxui.Theme) math.Size {
return math.Size{H: 34, W: math.MaxSize.W}
}
func (a *catAdap) ItemIndex(item gxui.AdapterItem) int {
if wine {
for i, v := range master[a.cat] {
if v.name == item {
return i
}
}
} else {
for i, v := range linmaster[a.cat] {
if v.name == item {
return i
}
}
}
return -1
}
+20 -133
View File
@@ -1,150 +1,37 @@
package main
import (
"bufio"
"os"
"path"
"reflect"
"sort"
"strings"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/drivers/gl"
"github.com/nelsam/gxui/themes/dark"
)
var (
appMaster map[string][]prtap
dr gxui.Driver
th gxui.Theme
master map[string][]app
linmaster map[string][]app
cats []string
conf *os.File
common string
commEnbl bool
lin []string
wine bool
comEnbld bool
)
type prtap struct {
name string
cat string
ex string
desc string
}
func main() {
commEnbl = true
appMaster = make(map[string][]prtap)
os.Mkdir("PortableApps", 0777)
os.Mkdir("PortableApps/LinuxPACom", 0777)
common = "PortableApps/LinuxPACom/common.sh"
_, err := os.Open(common)
if os.IsNotExist(err) {
commEnbl = false
_, err := os.Open("PortableApps/LinuxPACom/common.sh")
if err == nil {
comEnbld = true
}
pa, err := os.Open("PortableApps")
if err != nil {
panic(err)
}
appstmp, _ := pa.Readdir(-1)
var folds []string
for _, v := range appstmp {
if v.IsDir() && v.Name() != "LinuxPACom" {
folds = append(folds, v.Name())
}
}
sort.Strings(folds)
for _, v := range folds {
fi, _ := os.Open("PortableApps/" + v)
pat := processApp(fi)
if (pat != prtap{}) {
if _, ok := appMaster[pat.cat]; !ok {
cats = append(cats, pat.cat)
}
appMaster[pat.cat] = append(appMaster[pat.cat], pat)
}
}
gl.StartDriver(uiMain)
master = make(map[string][]app)
linmaster = make(map[string][]app)
gl.StartDriver(appMain)
}
func processApp(fi *os.File) (out prtap) {
fis, _ := fi.Readdir(-1)
if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
out.name = getName(fil)
fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
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 == "" {
out.name = path.Base(fi.Name())
}
if out.cat == "" {
out.cat = "other"
}
//executable detection
wd, _ := os.Getwd()
var rdr *bufio.Reader
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
}
}
}
}
return prtap{}
}
func getCat(fi *os.File) (out string) {
rdr := bufio.NewReader(fi)
var err error
var ln []byte
for err == nil {
ln, _, err = rdr.ReadLine()
str := string(ln)
if strings.HasPrefix(str, "Category=") {
out = strings.TrimPrefix(str, "Category=")
return
}
}
return
}
func getName(fi *os.File) (out string) {
rdr := bufio.NewReader(fi)
var err error
var ln []byte
for err == nil {
ln, _, err = rdr.ReadLine()
str := string(ln)
if strings.HasPrefix(str, "Name=") {
out = strings.TrimPrefix(str, "Name=")
return
}
}
return
func appMain(dri gxui.Driver) {
dr = dri
th = dark.CreateTheme(dr)
setup()
ui()
}
-103
View File
@@ -1,103 +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
apps []prtap
}
func (p *prtapAdap) SetApps(apps []prtap) {
p.apps = apps
p.DataChanged(false)
}
func (p *prtapAdap) Count() int {
return len(p.apps)
}
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.apps[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.apps[index].name)
box.AddChild(lbl)
return box
}
func (p *prtapAdap) ItemAt(index int) gxui.AdapterItem {
return p.apps[index]
}
func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int {
it, ok := item.(prtap)
if !ok {
return -1
}
for i, v := range p.apps {
if v == it {
return i
}
}
return -1
}
func (p *prtapAdap) Size(gxui.Theme) math.Size {
return math.Size{W: math.MaxSize.W, H: 36}
}
+176
View File
@@ -0,0 +1,176 @@
package main
import (
"bufio"
"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() {
panic("PortableApps folder not found!!")
}
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 {
lin = append(lin, ap.cat)
sort.Strings(lin)
}
} else {
if len(ap.lin) != 0 {
ind := sort.SearchStrings(lin, ap.cat)
if ind == len(lin) {
lin = append(lin, ap.cat)
sort.Strings(lin)
}
}
}
if len(ap.lin) != 0 {
linmaster[ap.cat] = append(linmaster[ap.cat], ap)
}
master[ap.cat] = append(master[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.HasPrefix(strings.ToLower(string(btys)), "ELF") || 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 {
ind := sort.SearchStrings(pics, "appicon_32.png")
if ind == len(pics) {
ind--
}
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
View File
+46 -44
View File
@@ -3,62 +3,64 @@ package main
import (
"os"
"os/exec"
"path"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/themes/dark"
)
var (
dr gxui.Driver
)
func uiMain(dri gxui.Driver) {
dr = dri
catAdap := &StrList{}
catAdap.SetStrings(cats)
appAdap := &prtapAdap{}
th := dark.CreateTheme(dr)
func ui() {
catListAdap := &StrList{}
appListAdap := &catAdap{}
catListAdap.SetStrings(lin)
win := th.CreateWindow(500, 500, "LinuxPA")
top := th.CreateLinearLayout()
top.SetDirection(gxui.BottomToTop)
top.SetHorizontalAlignment(gxui.AlignRight)
splBox := th.CreateLinearLayout()
spl := th.CreateSplitterLayout()
spl.SetOrientation(gxui.Horizontal)
catlist := th.CreateList()
catlist.SetAdapter(catAdap)
catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
str := it.(string)
appAdap.SetApps(appMaster[str])
catList := th.CreateList()
catList.SetAdapter(catListAdap)
catList.OnSelectionChanged(func(it gxui.AdapterItem) {
appListAdap.setCat(it.(string))
})
applist := th.CreateList()
applist.SetAdapter(appAdap)
spl.AddChild(catlist)
spl.AddChild(applist)
but := th.CreateLinearLayout()
but.SetDirection(gxui.RightToLeft)
launch := th.CreateButton()
launch.SetText("Launch!")
launch.OnClick(func(gxui.MouseEvent) {
if appAdap.ItemIndex(applist.Selected()) != -1 {
app := applist.Selected().(prtap)
dir, fi := path.Split(app.ex)
var cmd *exec.Cmd
if commEnbl {
cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
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 {
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
catListAdap.SetStrings(lin)
wineBut.SetText("Show Windows Apps")
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Start()
})
_, 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)
}
})
but.AddChild(launch)
top.AddChild(but)
top.AddChild(spl)
butBox.AddChild(wineBut)
}
top.AddChild(butBox)
top.AddChild(splBox)
win.AddChild(top)
win.OnClose(func() {
dr.Terminate()
})
win.OnClose(dr.Terminate)
}