6 Commits

Author SHA1 Message Date
Caleb be64aa083f Added beta update support.
Started work on further appimage support
2018-06-04 17:34:15 -05:00
Belac 3111705cae Removed legacy gxui 2018-06-03 02:48:40 -05:00
Belac Darkstorm 868ae8f700 Update README.md 2018-01-01 16:21:45 -06:00
Caleb Gardner 226e9d6210 Changed $PANAME to $FILENAME
Added $APPNAME
Fixed a couple bugs
2017-08-10 19:05:54 -05:00
Belac Darkstorm 56748f043e Added stuff for appimages.
Shows changelog before updating.
2017-08-09 03:36:35 -05:00
Belac Darkstorm 3d3239fe0a Updated README 2017-08-08 12:39:41 -05:00
11 changed files with 319 additions and 454 deletions
+7 -3
View File
@@ -30,6 +30,10 @@ Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6). The screenshot
# TODO (Might be in order) # TODO (Might be in order)
1. MAKE IT BETTER   1. MAKE IT BETTER  
1. Ask if you want to update   1. Manual update check  
1. Better appimage support in general 1. Better AppImage integrations (Specifically updating, getting information from the appimage, and better appimage downloading)
1. Check if all apps are closed when it closes and ask if you want to force stop the apps. . 1. Automagic appimage updating (It will of course ask you beforehand)
1. Get information (such as name and icon) directly from an appimage
1. Better appimage downloading (probably based around [AppImageHub](https://appimage.github.io/apps/))
1. Sandboxing support
1. Check if all apps are closed when it closes and ask if you want to force stop the apps
+43 -11
View File
@@ -25,7 +25,11 @@ type app struct {
func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter { func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter {
it := store.Append(nil) it := store.Append(nil)
store.SetValue(it, 0, a.icon) store.SetValue(it, 0, a.icon)
store.SetValue(it, 1, a.name) if portableHide {
store.SetValue(it, 1, strings.TrimSuffix(a.name, "Portable"))
} else {
store.SetValue(it, 1, a.name)
}
if len(a.ex) > 1 { if len(a.ex) > 1 {
if wine { if wine {
for _, v := range a.ex { for _, v := range a.ex {
@@ -48,13 +52,17 @@ func (a *app) launch() {
var cmd *exec.Cmd var cmd *exec.Cmd
if !contains(a.lin, a.ex[0]) { if !contains(a.lin, a.ex[0]) {
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} }
} else { } else {
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[0]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[0]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[0]+".config", 0777)
}
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} }
@@ -64,8 +72,12 @@ func (a *app) launch() {
cmd.Start() cmd.Start()
} else { } else {
var cmd *exec.Cmd var cmd *exec.Cmd
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[0]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[0]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[0]+".config", 0777)
}
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} }
@@ -78,7 +90,7 @@ func (a *app) launch() {
var cmd *exec.Cmd var cmd *exec.Cmd
if len(a.lin) == 0 { if len(a.lin) == 0 {
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} }
@@ -90,8 +102,12 @@ func (a *app) launch() {
break break
} }
} }
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[ind]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[ind]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[ind]+".config", 0777)
}
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[ind]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} }
@@ -109,8 +125,12 @@ func (a *app) launch() {
} }
} }
var cmd *exec.Cmd var cmd *exec.Cmd
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[ind]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[ind]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[ind]+".config", 0777)
}
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[ind]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} }
@@ -127,13 +147,17 @@ func (a *app) launchSub(sub int) {
var cmd *exec.Cmd var cmd *exec.Cmd
if !contains(a.lin, a.ex[sub]) { if !contains(a.lin, a.ex[sub]) {
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
} }
} else { } else {
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[sub]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[sub]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[sub]+".config", 0777)
}
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[sub]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} }
@@ -143,8 +167,12 @@ func (a *app) launchSub(sub int) {
cmd.Start() cmd.Start()
} else { } else {
var cmd *exec.Cmd var cmd *exec.Cmd
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[sub]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[sub]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[sub]+".config", 0777)
}
if comEnbld { if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"") cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[sub]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} else { } else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"") cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} }
@@ -179,11 +207,15 @@ func (a *app) edit(parent *gtk.Window, reload func()) {
imgBut.SetImage(img) imgBut.SetImage(img)
imgBut.SetSizeRequest(100, 100) imgBut.SetSizeRequest(100, 100)
imgBut.Connect("clicked", func() { imgBut.Connect("clicked", func() {
fil, _ := gtk.FileChooserDialogNewWith2Buttons("Select Icon", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Cancel", gtk.RESPONSE_CANCEL, "Open", gtk.RESPONSE_ACCEPT) fil, _ := gtk.FileChooserDialogNewWith1Button("Select Icon", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Open", gtk.RESPONSE_ACCEPT)
filter, _ := gtk.FileFilterNew() filter, _ := gtk.FileFilterNew()
filter.AddPixbufFormats() filter.AddPixbufFormats()
filter.SetName("Supported Pictures") filter.SetName("Supported Pictures")
fil.AddFilter(filter) fil.AddFilter(filter)
but, _ := fil.AddButton("Cancel", gtk.RESPONSE_CANCEL)
but.Connect("clicked", func() {
fil.Close()
})
resp := fil.Run() resp := fil.Run()
if resp == int(gtk.RESPONSE_ACCEPT) { if resp == int(gtk.RESPONSE_ACCEPT) {
filename := fil.GetFilename() filename := fil.GetFilename()
+78
View File
@@ -0,0 +1,78 @@
package appimg
// Thanks to probono for the majority of this C code: https://discourse.appimage.org/t/accessing-appimage-desktop-file/173/4?u=calebq42
/*
#cgo CFLAGS: -I/usr/lib
#cgo LDFLAGS: -L/usr/lib/libappimage.so -lappimage
#cgo pkg-config: glib-2.0
#include <appimage/appimage.h>
#include <stdlib.h>
#include <glib.h>
#include <strings.h>
bool extract_desktop(char* appimageLoc,char* extractLoc){
char** files = appimage_list_files(appimageLoc);
g_autofree gchar *desktop_file = NULL;
gchar *extracted_desktop_file = extractLoc;
int i = 0;
for (; files[i] != NULL ; i++) {
// g_debug("AppImage file: %s", files[i]);
if (g_str_has_suffix (files[i],".desktop")) {
desktop_file = files[i];
g_debug("AppImage desktop file: %s", desktop_file);
break;
}
}
if(desktop_file == NULL) {
g_debug("AppImage desktop file not found");
appimage_string_list_free(files);
return FALSE;
}
appimage_extract_file_following_symlinks(appimageLoc, desktop_file,extracted_desktop_file);
appimage_string_list_free(files);
return TRUE;
}
bool extract_file(char* appimageLoc,char* filename,char* extractLoc){
char** files = appimage_list_files(appimageLoc);
g_autofree gchar *found_file = NULL;
gchar *extracted_file = extractLoc;
int i = 0;
for (; files[i] != NULL ; i++) {
g_debug("AppImage file: %s", files[i]);
if (strcmp(files[i],filename)==0) {
found_file = files[i];
g_debug("FileFound: %s", found_file);
}
}
if(found_file == NULL) {
g_debug("filenotfound");
appimage_string_list_free(files);
return FALSE;
}
appimage_extract_file_following_symlinks(appimageLoc, found_file,extracted_file);
appimage_string_list_free(files);
return TRUE;
}
*/
import "C"
import (
"errors"
"os"
"unsafe"
)
func GetDesktopFile(loc string) (*os.File, error) {
os.Remove("/tmp/my.desktop")
var locTmp *C.char = C.CString(loc)
defer C.free(unsafe.Pointer(locTmp))
var extractLoc *C.char = C.CString("/tmp/my.desktop")
defer C.free(unsafe.Pointer(extractLoc))
var out C.bool = C.extract_desktop(locTmp, extractLoc)
if out == false {
return nil, errors.New("Desktop File Not Found!")
}
return os.Open("/tmp/my.desktop")
}
+1 -1
View File
@@ -53,7 +53,7 @@ func downloadApp(parent *gtk.Window, ap appimg) {
foldName = "PortableApps/" + name foldName = "PortableApps/" + name
} else { } else {
os.Mkdir("PortableApps/"+name+"Portable", 0777) os.Mkdir("PortableApps/"+name+"Portable", 0777)
foldName = "PortableApps/" + name foldName = "PortableApps/" + name + "Portable"
} }
os.Remove(foldName + "/" + ap.full) os.Remove(foldName + "/" + ap.full)
fil, err := os.Create(foldName + "/" + ap.full) fil, err := os.Create(foldName + "/" + ap.full)
-82
View File
@@ -1,82 +0,0 @@
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
@@ -1,208 +0,0 @@
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
}
-65
View File
@@ -1,65 +0,0 @@
package main
import (
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/math"
)
//StrList TODO
type StrList struct {
gxui.AdapterBase
strs []string
}
//AddString TODO
func (s *StrList) AddString(add string) {
s.strs = append(s.strs, add)
s.DataChanged(false)
}
//Remove TODO
func (s *StrList) Remove(index int) {
s.strs = append(s.strs[:index], s.strs[index+1:]...)
s.DataChanged(false)
}
//SetStrings TODO
func (s *StrList) SetStrings(strs []string) {
s.strs = strs
s.DataChanged(false)
}
//Count TODO
func (s *StrList) Count() int {
return len(s.strs)
}
//ItemAt TODO
func (s *StrList) ItemAt(index int) gxui.AdapterItem {
return s.strs[index]
}
//ItemIndex TODO
func (s *StrList) ItemIndex(item gxui.AdapterItem) int {
for i, v := range s.strs {
if v == item {
return i
}
}
return -1
}
//Create TODO
func (s *StrList) Create(th gxui.Theme, index int) gxui.Control {
box := th.CreateLinearLayout()
box.SetDirection(gxui.LeftToRight)
lbl := th.CreateLabel()
lbl.SetText(s.strs[index])
box.AddChild(lbl)
return box
}
//Size TODO
func (s *StrList) Size(gxui.Theme) math.Size {
return math.Size{W: math.MaxSize.W, H: 20}
}
-66
View File
@@ -1,66 +0,0 @@
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)
}
+25 -5
View File
@@ -2,6 +2,7 @@ package main
import ( import (
"encoding/gob" "encoding/gob"
"flag"
"fmt" "fmt"
"os" "os"
@@ -9,8 +10,7 @@ import (
) )
const ( const (
version = "2.1.1.0" version = "2.1.4.0"
defIni = ""
) )
var ( var (
@@ -22,17 +22,21 @@ var (
comEnbld bool comEnbld bool
wineAvail bool wineAvail bool
portableHide bool portableHide bool
betaUpdate bool
versionNewest = true versionNewest = true
paDirs = true
) )
func main() { func main() {
forced := flag.Bool("force-update", false, "Force the update dialog to be shown")
flag.Parse()
os.MkdirAll("PortableApps/LinuxPACom", 0777) os.MkdirAll("PortableApps/LinuxPACom", 0777)
master = make(map[string][]app) master = make(map[string][]app)
linmaster = make(map[string][]app) linmaster = make(map[string][]app)
uiStart() uiStart(*forced)
} }
func uiStart() { func uiStart(forced bool) {
gtk.Init(nil) gtk.Init(nil)
setup() setup()
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
@@ -49,7 +53,7 @@ func uiStart() {
ui(win) ui(win)
win.ShowAll() win.ShowAll()
win.Show() win.Show()
update(win) update(win, forced)
gtk.Main() gtk.Main()
} }
@@ -72,6 +76,14 @@ func savePrefs() {
if err != nil { if err != nil {
return return
} }
err = enc.Encode(paDirs)
if err != nil {
return
}
err = enc.Encode(betaUpdate)
if err != nil {
return
}
} }
func loadPrefs() { func loadPrefs() {
@@ -92,6 +104,14 @@ func loadPrefs() {
if err != nil { if err != nil {
return return
} }
err = dec.Decode(&paDirs)
if err != nil {
return
}
err = dec.Decode(&betaUpdate)
if err != nil {
return
}
} }
func contains(arr []string, str string) bool { func contains(arr []string, str string) bool {
+46
View File
@@ -9,6 +9,10 @@ import (
"github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/gtk"
) )
const (
commonHelp = "The common.sh is run before every app is launched and allows you to set variables such as $HOME. For directories, ALWAYS start the directory with $PWD which points to the directory where LinuxPA is. To allow for greater customization and isolation, you can use the $FILENAME variable which is the filename of the executable you're using and the $APPNAME variable which is the name of the app being lanched."
)
func settingsUI(parent *gtk.Window, onExit func()) { func settingsUI(parent *gtk.Window, onExit func()) {
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL) win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.SetTransientFor(parent) win.SetTransientFor(parent)
@@ -84,11 +88,19 @@ func settingsUI(parent *gtk.Window, onExit func()) {
versCheck.Connect("toggled", func() { versCheck.Connect("toggled", func() {
versionNewest = versCheck.GetActive() versionNewest = versCheck.GetActive()
}) })
paDirsCheck, _ := gtk.CheckButtonNewWithLabel("Create .home and .config directories for AppImages")
paDirsCheck.SetActive(paDirs)
paDirsCheck.Connect("toggled", func() {
paDirs = paDirsCheck.GetActive()
})
betaCheck, _ := gtk.CheckButtonNewWithLabel("Update to beta releases")
gnrl.Add(wineLbl) gnrl.Add(wineLbl)
gnrl.Add(dlWine) gnrl.Add(dlWine)
gnrl.Add(pthdCheck) gnrl.Add(pthdCheck)
gnrl.Add(wineCheck) gnrl.Add(wineCheck)
gnrl.Add(versCheck) gnrl.Add(versCheck)
gnrl.Add(paDirsCheck)
gnrl.Add(betaCheck)
ntbk.AppendPage(gnrl, getLabel("General")) ntbk.AppendPage(gnrl, getLabel("General"))
com, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5) com, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
com.SetMarginStart(10) com.SetMarginStart(10)
@@ -113,8 +125,25 @@ func settingsUI(parent *gtk.Window, onExit func()) {
cnl.Connect("clicked", func() { cnl.Connect("clicked", func() {
setupTxt(comBuf) setupTxt(comBuf)
}) })
info, _ := gtk.ButtonNewWithLabel("Info")
info.Connect("clicked", func() {
infoBox, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
infoBox.SetTransientFor(parent)
infoBox.SetDefaultSize(300, 80)
infoBox.SetName("common.sh info")
infoBox.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
infolbl, _ := gtk.LabelNew(commonHelp)
infolbl.SetLineWrap(true)
infolbl.SetSizeRequest(200, 50)
box.Add(infolbl)
infoBox.Add(box)
infoBox.ShowAll()
infoBox.Show()
})
svBox.Add(sv) svBox.Add(sv)
svBox.Add(cnl) svBox.Add(cnl)
svBox.Add(info)
com.Add(comScrl) com.Add(comScrl)
com.Add(svBox) com.Add(svBox)
ntbk.AppendPage(com, getLabel("common.sh")) ntbk.AppendPage(com, getLabel("common.sh"))
@@ -136,8 +165,25 @@ func settingsUI(parent *gtk.Window, onExit func()) {
dlWine.SetTooltipText("") dlWine.SetTooltipText("")
} }
}) })
in, _ := gtk.ButtonNewWithLabel("Info")
in.Connect("clicked", func() {
infoBox, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
infoBox.SetTransientFor(parent)
infoBox.SetDefaultSize(300, 80)
infoBox.SetName("common.sh info")
infoBox.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
infolbl, _ := gtk.LabelNew(commonHelp)
infolbl.SetLineWrap(true)
infolbl.SetSizeRequest(200, 50)
box.Add(infolbl)
infoBox.Add(box)
infoBox.ShowAll()
infoBox.Show()
})
mkCom.Show() mkCom.Show()
com.Add(mkCom) com.Add(mkCom)
com.Add(in)
} else { } else {
setupTxt(comBuf) setupTxt(comBuf)
} }
+119 -13
View File
@@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
@@ -14,8 +15,10 @@ import (
) )
const ( const (
versionURL = "https://www.dropbox.com/s/a0xizzo0a4vsfqt/Version?dl=1" versionURL = "https://www.dropbox.com/s/a0xizzo0a4vsfqt/Version?dl=1"
downloadURL = "https://github.com/CalebQ42/LinuxPA/releases/download/vXXX/LinuxPA" downloadURL = "https://github.com/CalebQ42/LinuxPA/releases/download/vXXX/LinuxPA"
changelogURL = "https://www.dropbox.com/s/nmbk318er5kej5h/Changelog?dl=1"
changelogBetaURL = "https://www.dropbox.com/s/m8mo2o3nsvfqbfx/ChangelogBeta?dl=1"
) )
//Thanks to https://www.socketloop.com/tutorials/golang-download-file-example //Thanks to https://www.socketloop.com/tutorials/golang-download-file-example
@@ -45,17 +48,61 @@ func versionDL() (bool, error) {
return true, nil return true, nil
} }
func getVersionFileInfo() string { func getVersionFileInfo() (stable string, beta string) {
fil, err := os.Open("PortableApps/LinuxPACom/Version") fil, err := os.Open("PortableApps/LinuxPACom/Version")
if err != nil { if err != nil {
return "Error!" return "Error!", ""
} }
rdr := bufio.NewReader(fil) rdr := bufio.NewReader(fil)
out, _, _ := rdr.ReadLine() out, _, _ := rdr.ReadLine()
stable = string(out)
out, _, _ = rdr.ReadLine()
beta = string(out)
return
}
func changelogDL() (bool, error) {
changelogFile, err := os.Create("PortableApps/LinuxPACom/Changelog")
if err != nil {
return false, err
}
changelogFile.Chmod(0777)
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
var response *http.Response
if betaUpdate {
response, err = check.Get(changelogBetaURL)
} else {
response, err = check.Get(changelogURL)
}
if err != nil {
return false, err
}
_, err = io.Copy(changelogFile, response.Body)
if err != nil {
return false, err
}
return true, nil
}
func getChangelog() string {
fil, err := os.Open("PortableApps/LinuxPACom/Changelog")
if err != nil {
return "Error!"
}
out, _ := ioutil.ReadAll(fil)
return string(out) return string(out)
} }
func checkForUpdate(new string) (bool, error) { func checkForUpdate(stable, beta string) (bool, error) {
new := stable
if betaUpdate {
new = beta
}
curSlice := strings.Split(version, ".") curSlice := strings.Split(version, ".")
newSlice := strings.Split(new, ".") newSlice := strings.Split(new, ".")
curNums := make([]int, 4) curNums := make([]int, 4)
@@ -111,13 +158,69 @@ func downloadUpdate(newVersion string) (bool, error) {
return true, nil return true, nil
} }
func update(win *gtk.Window) { func update(win *gtk.Window, forced bool) {
stat, err := versionDL()
if stat {
stable, beta := getVersionFileInfo()
if stable != "Error!" {
stat, err = checkForUpdate(stable, beta)
if stat || forced {
stat, err = changelogDL()
if stat {
updateWin, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
updateWin.SetTransientFor(win)
updateWin.SetPosition(gtk.WIN_POS_CENTER)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
lbl, _ := gtk.LabelNew("There's a new update! Here's the changelog:")
tagTbl, _ := gtk.TextTagTableNew()
buf, _ := gtk.TextBufferNew(tagTbl)
tv, _ := gtk.TextViewNewWithBuffer(buf)
tv.SetEditable(false)
buf.SetText(getChangelog())
butBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
upBut, _ := gtk.ButtonNewWithLabel("Update")
upBut.Connect("clicked", func() {
updateWin.Close()
actuallyUpdate(win, forced)
})
cnlBut, _ := gtk.ButtonNewWithLabel("Cancel")
cnlBut.Connect("clicked", func() {
updateWin.Close()
})
butBox.Add(upBut)
butBox.Add(cnlBut)
topLvl.Add(lbl)
topLvl.Add(tv)
topLvl.Add(butBox)
topLvl.SetMarginBottom(10)
topLvl.SetMarginEnd(10)
topLvl.SetMarginStart(10)
topLvl.SetMarginTop(10)
updateWin.Add(topLvl)
updateWin.ShowAll()
updateWin.Show()
} else {
fmt.Println(err)
}
} else {
fmt.Println(err)
}
} else {
fmt.Println("Failed Version File Info")
}
} else {
fmt.Println(err)
}
}
func actuallyUpdate(win *gtk.Window, forced bool) {
updateWin, _ := gtk.WindowNew(gtk.WINDOW_POPUP) updateWin, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
updateWin.SetTransientFor(win) updateWin.SetTransientFor(win)
updateWin.SetSizeRequest(150, 50)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5) topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
spin, _ := gtk.SpinnerNew() spin, _ := gtk.SpinnerNew()
spin.Start() spin.Start()
lbl, _ := gtk.LabelNew("Checking for updates") lbl, _ := gtk.LabelNew("Updating")
topLvl.Add(spin) topLvl.Add(spin)
topLvl.Add(lbl) topLvl.Add(lbl)
topLvl.SetMarginBottom(10) topLvl.SetMarginBottom(10)
@@ -132,12 +235,15 @@ func update(win *gtk.Window) {
defer updateWin.Close() defer updateWin.Close()
stat, err := versionDL() stat, err := versionDL()
if stat { if stat {
res := getVersionFileInfo() stable, beta := getVersionFileInfo()
if res != "Error!" { if stable != "Error!" {
stat, err = checkForUpdate(res) stat, err = checkForUpdate(stable, beta)
if stat { if stat || forced {
lbl.SetText("Updating!") if betaUpdate {
downloadUpdate(res) downloadUpdate(beta)
} else {
downloadUpdate(stable)
}
win.Close() win.Close()
cmd := exec.Command("./LinuxPA") cmd := exec.Command("./LinuxPA")
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin