17 Commits

Author SHA1 Message Date
Belac Darkstorm 3b639f53fd Merge pull request #6 from CalebQ42/gtkUI
Gtk ui
2017-04-04 18:36:18 -05:00
Belac Darkstorm 3199ad88fd Finishing up gui 2017-04-04 18:35:28 -05:00
Belac Darkstorm a221d18d33 Starting UI remake work 2017-04-04 07:54:04 -05:00
Belac Darkstorm a9eeb3bb1c Last push before GUI redo 2017-04-04 01:32:13 -05:00
Belac Darkstorm 844a282fd7 Wine download finished for later on.
Going to start switching to another GUI library
2017-04-04 01:23:17 -05:00
Belac Darkstorm 9da352a315 Updating is working!! 2017-04-03 10:43:22 -05:00
Belac Darkstorm 34b8f7c926 Forgot to implement updating 2017-04-03 09:23:41 -05:00
Belac Darkstorm 5d5cedec58 Ready to test then bug fix :)
Also, I'm ALIVE!!!!
2017-04-03 09:17:49 -05:00
Belac Darkstorm 8441a8b752 Working on an auto-update mechanism 2017-04-03 08:23:25 -05:00
Belac Darkstorm d64d88e0a5 Tries to make PortableApps folder before failing 2016-09-23 14:32:30 -05:00
Belac Darkstorm 5eeb9cc702 Fixed some bugs (oops) 2016-09-22 20:25:26 -05:00
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
12 changed files with 1232 additions and 372 deletions
+10 -4
View File
@@ -1,11 +1,16 @@
# LinuxPA
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 (.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
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 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,10 +20,10 @@ Because apps aren't natively formated in the PortableApps.com format, if LinuxPA
# 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 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
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
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
@@ -29,3 +34,4 @@ Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
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 (Should be able to get a working version from PlayOnLinux, but I need to add a check to see if filesystem is EXT as Wine doesn't like filesystems w/o permission control)
+308
View File
@@ -0,0 +1,308 @@
package main
import (
"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 {
for _, v := range a.ex {
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]) {
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 {
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]) {
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()
}
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()
}
// type appExNode struct {
// ap app
// exInd int
// }
//
// func (a *appExNode) launch() {
// if wine {
// var cmd *exec.Cmd
// if !contains(a.ap.lin, a.ap.ex[a.exInd]) {
// 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
// }
// func (a *appNode) Count() int {
// if wine {
// if len(a.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
// }
+82
View File
@@ -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
}
+208
View File
@@ -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
View File
+66
View File
@@ -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)
}
+40 -164
View File
@@ -1,183 +1,59 @@
package main
import (
"bufio"
"fmt"
"os"
"path"
"reflect"
"sort"
"strings"
"github.com/nelsam/gxui/drivers/gl"
"github.com/gotk3/gotk3/gtk"
)
const (
version = "2.0.0.1"
defIni = ""
)
var (
appMaster map[string][]prtap
master map[string][]app
linmaster map[string][]app
cats []string
wineOnly []string
linOnly []string
conf *os.File
common string
commEnbl bool
lin []string
wine bool
comEnbld bool
darkTheme = true
)
type prtap struct {
name string
cat string
ex string
desc string
wine bool
}
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
}
pa, err := os.Open("PortableApps")
os.MkdirAll("PortableApps/LinuxPACom", 0777)
master = make(map[string][]app)
linmaster = make(map[string][]app)
uiStart()
}
func uiStart() {
gtk.Init(nil)
setup()
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
if err != nil {
panic(err)
fmt.Println("Window not created", err)
}
appstmp, _ := pa.Readdir(-1)
var folds []string
for _, v := range appstmp {
if v.IsDir() && v.Name() != "LinuxPACom" && v.Name() != "PortableApps.com" {
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 {
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)
win.SetTitle("LinuxPA")
win.Connect("destroy", func() {
gtk.MainQuit()
})
win.SetDefaultSize(500, 500)
win.SetPosition(gtk.WIN_POS_CENTER)
ui(win)
win.ShowAll()
win.Show()
update(win)
gtk.Main()
}
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
}
}
func contains(arr []string, str string) bool {
for _, v := range arr {
if v == str {
return true
}
}
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) {
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
return false
}
-130
View File
@@ -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}
}
+204
View File
@@ -0,0 +1,204 @@
package main
import (
"bufio"
"fmt"
_ "image/png"
"os"
"reflect"
"sort"
"strings"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)
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) *gdk.Pixbuf {
var pic string
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 if _, err := os.Open(fold + "/appicon.png"); err == nil {
pic = fold + "/appicon.png"
} else {
img, _ := gtk.ImageNewFromIconName("application-x-executable", gtk.ICON_SIZE_BUTTON)
buf, _ := img.GetPixbuf().ScaleSimple(32, 32, gdk.INTERP_BILINEAR)
return buf
}
img, _ := gtk.ImageNewFromFile(pic)
buf, _ := img.GetPixbuf().ScaleSimple(32, 32, gdk.INTERP_BILINEAR)
return buf
}
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
}
+113 -74
View File
@@ -2,89 +2,128 @@ package main
import (
"fmt"
"os"
"os/exec"
"path"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/themes/dark"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
var (
dr gxui.Driver
)
func uiMain(dri gxui.Driver) {
dr = dri
catAdap := &StrList{}
catAdap.SetStrings(linOnly)
appAdap := &prtapAdap{}
appAdap.Wine(false)
th := dark.CreateTheme(dr)
win := th.CreateWindow(500, 500, "LinuxPA")
top := th.CreateLinearLayout()
top.SetDirection(gxui.BottomToTop)
top.SetHorizontalAlignment(gxui.AlignRight)
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])
func ui(win *gtk.Window) {
ls := getCatRows()
var treeApps []*gtk.TreeIter
header, _ := gtk.HeaderBarNew()
header.SetShowCloseButton(true)
header.SetTitle("LinuxPA")
header.SetSubtitle("PortableApps.com type launcher")
settings, _ := gtk.ButtonNewFromIconName("applications-system", gtk.ICON_SIZE_SMALL_TOOLBAR)
settings.Connect("clicked", func() {
//Open Settings window!
})
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 app.wine {
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; wine \""+fi+"\"")
settings.SetTooltipText("Settings (Coming Soon!)")
header.PackStart(settings)
win.SetTitlebar(header)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0)
lrBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
catList, _ := gtk.ListBoxNew()
catList.SetActivateOnSingleClick(true)
store, _ := gtk.TreeStoreNew(glib.TYPE_OBJECT, glib.TYPE_STRING)
appsList, _ := gtk.TreeViewNewWithModel(store)
render, _ := gtk.CellRendererPixbufNew()
pixColumn, _ := gtk.TreeViewColumnNewWithAttribute("", render, "pixbuf", 0)
txtRender, _ := gtk.CellRendererTextNew()
txtColumn, _ := gtk.TreeViewColumnNewWithAttribute("", txtRender, "text", 1)
appsList.AppendColumn(pixColumn)
appsList.AppendColumn(txtColumn)
catList.SetHExpand(true)
catList.SetVExpand(true)
appsList.SetHExpand(true)
appsList.SetVExpand(true)
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
vScrollApp, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
hScrollApp, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
catScrl, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
catScrl.Add(catList)
appScrl, _ := gtk.ScrolledWindowNew(hScrollApp, vScrollApp)
appScrl.Add(appsList)
lrBox.Add(catScrl)
lrBox.Add(appScrl)
botBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 2)
wineCheck, _ := gtk.CheckButtonNewWithLabel("Show Windows apps (Wine)")
wineCheck.Connect("toggled", func() {
wine = wineCheck.GetActive()
for i := range ls {
catList.Remove(catList.GetRowAtIndex(i))
}
ls = getCatRows()
for _, v := range ls {
catList.Add(v)
}
catList.ShowAll()
})
botBox.Add(wineCheck)
topLvl.Add(lrBox)
topLvl.PackEnd(botBox, false, true, 0)
win.Add(topLvl)
for _, v := range ls {
catList.Prepend(v)
}
catList.Connect("row-selected", func() {
store.Clear()
if catList.GetSelectedRow().GetIndex() >= 0 {
treeApps = make([]*gtk.TreeIter, 0)
if wine {
apps := master[cats[catList.GetSelectedRow().GetIndex()]]
for _, v := range apps {
treeApps = append(treeApps, v.getTreeIter(store))
}
} else {
if commEnbl {
cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
apps := linmaster[lin[catList.GetSelectedRow().GetIndex()]]
for _, v := range apps {
treeApps = append(treeApps, v.getTreeIter(store))
}
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
})
if _, err := exec.LookPath("wine"); err == nil {
fmt.Println("Wine found!")
wine := th.CreateButton()
wine.SetType(gxui.ToggleButton)
wine.OnClick(func(gxui.MouseEvent) {
if wine.IsChecked() {
catAdap.SetStrings(cats)
appAdap.Wine(true)
} else {
catAdap.SetStrings(linOnly)
appAdap.Wine(false)
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 {
app := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
app.launch()
} else {
app := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
app.launch()
}
} else if len(ind) == 2 {
if wine {
app := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
app.launchSub(ind[1])
} else {
app := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
app.launchSub(ind[1])
}
}
})
wine.SetText("Show Windows Apps")
wine.SetChecked(appAdap.wine)
but.AddChild(wine)
} else {
fmt.Println("Wine not found!")
}
but.AddChild(launch)
top.AddChild(but)
top.AddChild(spl)
win.AddChild(top)
win.OnClose(func() {
dr.Terminate()
}
})
}
func getCatRows() (out []*gtk.Label) {
if wine {
for _, v := range cats {
txt, _ := gtk.LabelNew(v)
out = append(out, txt)
fmt.Println(v)
}
} else {
for _, v := range lin {
txt, _ := gtk.LabelNew(v)
out = append(out, txt)
fmt.Println(v)
}
}
return
}
+159
View File
@@ -0,0 +1,159 @@
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_TOPLEVEL)
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) {
stat, err := versionDL()
if stat {
res := getVersionFileInfo()
if res != "Error!" {
stat, err = checkForUpdate(res)
if stat {
lbl.SetText("Updating!")
downloadUpdate(res)
updateWin.Close()
win.Close()
cmd := exec.Command("./LinuxPA")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Start()
} else {
fmt.Println(err)
updateWin.Close()
}
} else {
fmt.Println("Failed Version File Info")
updateWin.Close()
}
} else {
fmt.Println(err)
updateWin.Close()
}
}(win, updateWin)
}
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"io"
"net/http"
"os"
"github.com/mholt/archiver"
)
const (
wineURL = "https://www.playonlinux.com/wine/binaries/linux-amd64/PlayOnLinux-wine-2.5-linux-amd64.pol"
)
func downloadWine() (bool, error) {
wineTar, err := os.Create("PortableApps/LinuxPACom/wine2.5.tar.bz2")
if err != nil {
return false, err
}
wineTar.Chmod(0777)
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 {
return false, err
}
defer resp.Body.Close()
_, err = io.Copy(wineTar, resp.Body)
if err != nil {
return false, err
}
err = archiver.TarBz2.Open("PortableApps/LinuxPACom/wine2.5.tar.bz2", "PortableApps/LinuxPACom/Wine")
if err != nil {
return false, err
}
return true, nil
}