35 Commits

Author SHA1 Message Date
Caleb Gardner ff48fae713 Messing arround with gioui 2024-10-18 06:43:39 -05:00
Caleb Gardner 645f2d8dd9 Switch to gioui 2024-10-17 07:00:17 -05:00
Caleb Gardner 90f47a3456 AppImage file to App 2024-09-28 06:28:54 -05:00
Caleb Gardner 096b5052a8 Set-up testing
Basic app directory parsing and executable detection
2024-09-27 06:48:12 -05:00
Caleb Gardner e3ca19c1d1 Reset to zero 2024-09-27 05:25:43 -05:00
Caleb Gardner e4e5adaf13 go mod tidy 2022-09-09 06:17:26 -05:00
Caleb Gardner 7a2ebd533e Update deps 2022-09-09 05:46:35 -05:00
Caleb Gardner 2f0ca5418c Updated readme and go version 2021-09-18 06:22:06 -05:00
Caleb Gardner ce9d4aed23 Fixed update download dialog 2020-11-28 03:52:10 -06:00
Caleb Gardner 712a5ab33d Removed stuff I don't need, now that I don't have a download UI 2020-11-28 03:33:50 -06:00
Caleb Gardner 6723f933b4 Forgot to up version number 2020-11-28 03:26:27 -06:00
Caleb Gardner 016fc35745 Download button now brings you to app image hub web page 2020-11-28 03:20:21 -06:00
Caleb Gardner ba5e3510ec some stuff for the future 2020-11-09 15:59:50 -06:00
Caleb Gardner 7e2d7ee14b Updated README 2020-11-09 15:30:14 -06:00
Caleb Gardner b20de4f1d6 Updated go.mod 2020-11-07 01:01:58 -06:00
Caleb Gardner d2e91baa6b Possibly full AppImage support 2020-11-06 04:54:22 -06:00
Caleb Gardner a0f22e480b Now using a new version of GoAppImage which should actually work.
Minor updates due to new library versions
Added go.mod to use Go's versioning system.
2020-11-06 03:44:34 -06:00
Belac Darkstorm 57f921c2cb Merge pull request #12 from probonopd/patch-1
https://appimage.github.io/
2019-01-18 18:37:35 -06:00
probonopd 55f897db46 https://appimage.github.io/ 2019-01-18 16:47:12 +00:00
Belac Darkstorm 3d9583281e AppImage's are now processed better
AppImage's desktop files are now extracted so name, category, and icon can be obtained
Made all icons be scaled so you don't get icons that are too big or small
2018-06-16 03:08:31 -05:00
Caleb ec4d66f6b2 Some refinement
Moved more complex appimage stuff to seperate package (github.com/CalebQ42/GoAppImage)
Moved settings to a seperate file for organization
Some work to allow asyncronouse app loading (Since goappimage is super slow)
Comments to show what's going to be there in the future.
2018-06-14 02:30:59 -05:00
Caleb c442ef5688 Removed debug code 2018-06-07 21:02:37 -05:00
Caleb 78d3723bf4 Finished work on AppImage desktop file extraction 2018-06-07 13:58:47 -05:00
Caleb 828b9f4cda Fixed a couple bugs relating to settings and wine apps 2018-06-04 18:11:49 -05:00
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
Belac Darkstorm 6e643b68ac Update README.md 2017-08-08 07:02:09 -05:00
Belac Darkstorm 539f33d25e Updated README 2017-04-18 09:21:30 -05:00
Belac Darkstorm 4d3cb9f486 updated 2017-04-14 04:07:55 -05:00
Belac Darkstorm a55c82483a Better download list parsing 2017-04-14 03:36:50 -05:00
Belac Darkstorm 9e9bb82025 Moved "Show windows apps" to settings
Added "Hide Portable from app names"
2017-04-14 01:56:36 -05:00
21 changed files with 401 additions and 1895 deletions
+1
View File
@@ -0,0 +1 @@
/testing
+35 -19
View File
@@ -1,35 +1,51 @@
# LinuxPA
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
# 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.
## How to use
# 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)
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 it finds. .sh script files have priority over other executable files.
## Apps
The below place provides linux executables that don't need libs installed on the host system:
[https://appimage.github.io/](https://appimage.github.io/)
## PortableApps.com Compatibility
# PortableApps.com Compatibility
LinuxPA works will with the PortableApps.com launcher, as it looks for apps in the PortableApps folder and grabs the app's name and icon from where it should be in the PortableApps.com format.
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).
## common.sh
# 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 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=`
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). You can create and edit the common.sh from settings.
## Simple App Setup
Because apps aren't natively formated in the PortableApps.com format, LinuxPA will look in the root directory for a AppInfo.ini (for basic info such as category and name) and appicon.png. If they aren't found, it looks where the appicon_\*.png and AppInfo.ini is in PortableApps format. You can set what the AppInfo.ini and appicon.png are from LinuxPA.
## AppImage Support
# 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 later on.
I'm looking into improving AppImage support. As of 2.1.5.0 IF `unsquashfs` is in $PATH then some advanced AppImage support is available and it will automagically get the name and possibly the icon of it. I'm looking into better support, but it might be a while.
## USB mount
# USB mount
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)
## Screenshots
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6). The screenshots are with the adapta gtk theme
## TODO (Might be in order)
# TODO (Might be in order)
1. MAKE IT BETTER
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. Integrate [goappimage](https://github.com/probonod/go-appimage) library for better AppImage integration.
1. Try to `chmod +x` executables if they don't have the permission
1. Manual update check
1. Better AppImage integrations (Specifically updating and better appimage downloading)
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. Might be possible by packaging as an AppImage and providing Firejail, or simply just downloading it (like with Wine)
1. Check if all apps are closed when it closes and ask if you want to force stop the apps
+93 -261
View File
@@ -1,281 +1,113 @@
package main
import (
"bufio"
"fmt"
"bytes"
"log"
"os"
"os/exec"
"path/filepath"
"slices"
"strings"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
"github.com/probonopd/go-appimage/src/goappimage"
)
type app struct {
name string
cat string
appimg []string
lin []string
ex []string
icon *gdk.Pixbuf
dir string
ini *os.File
type ExeType byte
const (
Script = ExeType(iota + 1)
AppImage
ELF
Win
)
type Exe struct {
Filename string
Type ExeType
}
func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter {
it := store.Append(nil)
store.SetValue(it, 0, a.icon)
store.SetValue(it, 1, a.name)
if len(a.ex) > 1 {
if wine {
for _, v := range a.ex {
i := store.Append(it)
store.SetValue(i, 1, v)
}
} else {
for _, v := range a.lin {
i := store.Append(it)
store.SetValue(i, 1, v)
}
}
}
return it
type App struct {
Name string
Execs []Exe
// Image []byte TODO
}
func (a *app) launch() {
if len(a.ex) == 1 {
if wine {
var cmd *exec.Cmd
if !contains(a.lin, a.ex[0]) {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
}
} else {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
}
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
} else {
var cmd *exec.Cmd
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
} else {
if wine {
var cmd *exec.Cmd
if len(a.lin) == 0 {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
}
} else {
var ind int
for i, v := range a.lin {
if strings.HasSuffix(v, ".sh") {
ind = i
break
}
}
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
}
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
} else {
if len(a.lin) != 0 {
var ind int
for i, v := range a.lin {
if strings.HasSuffix(v, ".sh") {
ind = i
break
}
}
var cmd *exec.Cmd
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
}
}
}
func (a *app) launchSub(sub int) {
if wine {
var cmd *exec.Cmd
if !contains(a.lin, a.ex[sub]) {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
}
} else {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
}
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
} else {
var cmd *exec.Cmd
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
}
func (a *app) edit(parent *gtk.Window, reload func()) {
tmp := *a
parent.SetSensitive(false)
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.Connect("destroy", func() {
master = make(map[string][]app)
linmaster = make(map[string][]app)
cats = make([]string, 0)
lin = make([]string, 0)
setup()
reload()
parent.SetSensitive(true)
})
win.SetDefaultSize(400, 135)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
topLvl.SetMarginStart(10)
topLvl.SetMarginEnd(10)
topLvl.SetMarginTop(10)
topLvl.SetMarginBottom(10)
top, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
img, _ := gtk.ImageNewFromPixbuf(a.icon)
imgBut, _ := gtk.ButtonNew()
imgBut.SetImage(img)
imgBut.SetSizeRequest(100, 100)
imgBut.Connect("clicked", func() {
fil, _ := gtk.FileChooserDialogNewWith2Buttons("Select Icon", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Cancel", gtk.RESPONSE_CANCEL, "Open", gtk.RESPONSE_ACCEPT)
filter, _ := gtk.FileFilterNew()
filter.AddPixbufFormats()
filter.SetName("Supported Pictures")
fil.AddFilter(filter)
resp := fil.Run()
if resp == int(gtk.RESPONSE_ACCEPT) {
filename := fil.GetFilename()
_, err := os.Open(filename)
func ProcessAppImage(fil string) (*App, error) {
ai, err := goappimage.NewAppImage(fil)
if err != nil {
fmt.Println(err)
return
return nil, err
}
pix, _ := gdk.PixbufNewFromFileAtSize(filename, 32, 32)
tmp.icon = pix
img.SetFromPixbuf(pix)
fil.Close()
app := App{
Name: ai.Name,
// Image: ,
Execs: []Exe{
{
Filename: fil,
Type: AppImage,
},
},
}
})
topRt, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
nameLbl, _ := gtk.LabelNew("Name:")
nameLbl.SetHAlign(gtk.ALIGN_START)
txtgtbl, _ := gtk.TextTagTableNew()
txtBuf, _ := gtk.TextBufferNew(txtgtbl)
nameTxt, _ := gtk.TextViewNewWithBuffer(txtBuf)
nameTxt.SetAcceptsTab(false)
nameTxt.SetWrapMode(gtk.WRAP_CHAR)
nameTxt.SetPixelsBelowLines(5)
nameTxt.SetHExpand(true)
nameTxt.SetVExpand(false)
nameTxt.SetBorderWindowSize(gtk.TEXT_WINDOW_BOTTOM, 5)
txtBuf.SetText(tmp.name)
vScrollName, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
hScrollName, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
nameScr, _ := gtk.ScrolledWindowNew(hScrollName, vScrollName)
nameScr.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
nameScr.SetSizeRequest(300, 25)
nameScr.SetVExpand(false)
nameScr.Add(nameTxt)
catLbl, _ := gtk.LabelNew("Category:")
catLbl.SetHAlign(gtk.ALIGN_START)
catTbl, _ := gtk.TextTagTableNew()
catBuf, _ := gtk.TextBufferNew(catTbl)
catTxt, _ := gtk.TextViewNewWithBuffer(catBuf)
catBuf.SetText(tmp.cat)
catTxt.SetAcceptsTab(false)
catTxt.SetWrapMode(gtk.WRAP_CHAR)
catTxt.SetPixelsBelowLines(5)
catTxt.SetHExpand(true)
catTxt.SetVExpand(false)
catTxt.SetBorderWindowSize(gtk.TEXT_WINDOW_BOTTOM, 5)
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
catScr, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
catScr.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_NEVER)
catScr.SetSizeRequest(300, 25)
catScr.SetVExpand(false)
catScr.Add(catTxt)
topRt.Add(nameLbl)
topRt.Add(nameScr)
topRt.Add(catLbl)
topRt.Add(catScr)
top.Add(imgBut)
top.Add(topRt)
bot, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
sv, _ := gtk.ButtonNewWithLabel("Save")
sv.Connect("clicked", func() {
tmp.name, _ = txtBuf.GetText(txtBuf.GetStartIter(), txtBuf.GetEndIter(), true)
tmp.cat, _ = catBuf.GetText(catBuf.GetStartIter(), catBuf.GetEndIter(), true)
tmp.makeIni()
os.Remove(a.dir + "/appicon.png")
tmp.icon.SavePNG(a.dir+"/appicon.png", 0)
win.Close()
})
cnl, _ := gtk.ButtonNewWithLabel("Cancel")
cnl.Connect("clicked", func() {
win.Close()
})
bot.PackEnd(sv, false, false, 0)
bot.PackEnd(cnl, false, false, 0)
topLvl.Add(top)
topLvl.Add(bot)
win.Add(topLvl)
win.ShowAll()
win.Show()
return &app, nil
}
func (a *app) makeIni() {
os.Remove(a.dir + "/appinfo.ini")
fil, err := os.Create(a.dir + "/appinfo.ini")
func ProcessDir(dir string) (*App, error) {
fils, err := os.ReadDir(dir)
if err != nil {
return
log.Printf("Unable to list files in %v: %v\n", dir, err)
return nil, err
}
ini := "[General]\n"
ini += "Category=" + a.cat + "\n"
ini += "Name=" + a.name + "\n"
wrt := bufio.NewWriter(fil)
wrt.WriteString(ini)
wrt.Flush()
app := App{
Name: filepath.Base(dir),
}
for _, f := range fils {
if f.IsDir() {
continue
}
var t ExeType
if strings.HasSuffix(strings.ToLower(f.Name()), ".exe") {
t = Win
} else {
fil, err := os.Open(filepath.Join(dir, f.Name()))
if err != nil {
log.Printf("Error opening %v: %v\n", filepath.Join(dir, f.Name()), err)
continue
}
startByts := make([]byte, 4)
_, err = fil.Read(startByts)
if err != nil {
log.Printf("Error reading starting bytes of %v: %v\n", filepath.Join(dir, f.Name()), err)
continue
}
if bytes.HasPrefix(startByts, []byte("#!")) {
t = Script
} else if bytes.Contains(bytes.ToLower(startByts), []byte("elf")) {
if strings.HasSuffix(strings.ToLower(f.Name()), ".so") || strings.Contains(strings.ToLower(f.Name()), ".so.") {
continue
}
if goappimage.IsAppImage(filepath.Join(dir, f.Name())) {
t = AppImage
} else {
t = ELF
}
}
}
if t != 0 {
app.Execs = append(app.Execs, Exe{
Filename: f.Name(),
Type: t,
})
}
}
if len(app.Execs) == 0 {
return nil, nil
}
slices.SortFunc(app.Execs, func(a, b Exe) int {
if a.Type > b.Type {
return 1
} else if a.Type < b.Type {
return -1
}
return strings.Compare(a.Filename, b.Filename)
})
//TODO: get "proper" name & icon, either from AppImage or PortableApps spec
return &app, nil
}
-60
View File
@@ -1,60 +0,0 @@
package appimg
import "reflect"
func convert(in string) (out []tag) {
for i := 0; i < len(in); i++ {
v := in[i]
if v == '<' {
for j := i; j < len(in); j++ {
val := in[j]
if val == '>' {
var tmp tag
tmp.process(in[i+1 : j+1])
if !tmp.end && tmp.typ == "a" {
tmp.index[0] = i
tmp.index[1] = j
nd := fndend(tmp, in[j+1:])
if !reflect.DeepEqual(nd, tag{}) {
tmp.Meat = in[j+1 : nd.index[0]]
out = append(out, tmp)
str := in[tmp.index[1]:nd.index[0]]
in = in[:i] + str + in[nd.index[1]+1:]
}
}
break
}
}
}
}
return
}
func fndend(fnt tag, area string) tag {
var count int
for i, v := range area {
if v == '<' {
for j, val := range area[i:] {
if val == '>' {
var tmp tag
tmp.process(area[i+1 : i+j+1])
if tmp.typ == fnt.typ {
if tmp.end {
if count == 0 {
tmp.index[0] = fnt.index[1] + 1 + i
tmp.index[1] = fnt.index[1] + j + i + 1
return tmp
}
count--
break
} else {
count++
break
}
}
}
}
}
}
return tag{}
}
-115
View File
@@ -1,115 +0,0 @@
package appimg
import "strings"
type tag struct {
typ string
end bool
params map[string]string
index [2]int
Meat string
}
func (t *tag) value(param string) string {
return t.params[param]
}
func (t *tag) setValue(param, value string) {
if t.params == nil {
t.params = make(map[string]string)
}
t.params[strings.TrimSpace(strings.ToLower(param))] = strings.TrimSpace(value)
}
func (t *tag) process(bbtag string) {
if strings.HasPrefix(bbtag, "/") {
t.end = true
t.typ = strings.ToLower(strings.TrimPrefix(bbtag[:len(bbtag)-1], "/"))
return
}
for i, v := range bbtag {
if v == '=' || v == ' ' || v == '>' {
t.typ = strings.ToLower(bbtag[:i])
switch v {
case '=':
if qt := bbtag[i+1]; qt == '\'' || qt == '"' {
for j := i + 2; j < len(bbtag); j++ {
if bbtag[j] == qt {
t.setValue("starting", bbtag[i+2:j])
bbtag = bbtag[j+1:]
break
} else if bbtag[j] == '>' {
t.setValue("starting", bbtag[i+2:j])
return
}
}
} else {
for j := i + 1; j < len(bbtag); j++ {
if bbtag[j] == '>' {
t.setValue("starting", bbtag[i+1:j])
return
} else if bbtag[j] == ' ' {
t.setValue("starting", bbtag[i+1:j])
bbtag = bbtag[j+1:]
break
}
}
}
case '>':
return
case ' ':
bbtag = bbtag[i:]
}
break
}
}
t.processFurther(bbtag)
}
func (t *tag) processFurther(further string) {
further = strings.TrimSpace(further)
for i := 0; i < len(further); i++ {
switch further[i] {
case ' ':
t.setValue(strings.ToLower(further[:i]), further[:i])
further = strings.TrimSpace(further[i:])
i = -1
case '=':
if qt := further[i+1]; qt == '\'' || qt == '"' {
outloopqt:
for j := i + 2; j < len(further); j++ {
switch further[j] {
case '>':
t.setValue(strings.ToLower(further[:i]), further[i+2:j])
return
case qt:
t.setValue(strings.ToLower(further[:i]), further[i+2:j])
further = strings.TrimSpace(further[j+1:])
i = -1
break outloopqt
}
}
} else {
outloop:
for j := i + 1; j < len(further); j++ {
switch further[j] {
case '>':
t.setValue(strings.ToLower(further[:i]), further[i+1:j])
return
case ' ':
t.setValue(strings.ToLower(further[:i]), further[i+1:j])
further = strings.TrimSpace(further[j:])
i = -1
break outloop
}
}
}
case '>':
if i != 0 {
t.setValue(strings.ToLower(further[:i]), further[:i])
return
}
return
}
}
}
-11
View File
@@ -1,11 +0,0 @@
package appimg
type appimg struct {
name string
}
func newApp(name string) appimg {
var out appimg
out.name = name
return out
}
-66
View File
@@ -1,66 +0,0 @@
package appimg
import (
"fmt"
"io"
"net/http"
"os"
"strings"
"github.com/gotk3/gotk3/gtk"
)
func downloadApp(parent *gtk.Window, ap appimg) {
parent.SetSensitive(false)
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.SetTransientFor(parent)
win.Connect("destroy", func() {
parent.SetSensitive(true)
})
spn, _ := gtk.SpinnerNew()
spn.Start()
lbl, _ := gtk.LabelNew("Downloading " + ap.name + "...")
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
box.SetMarginStart(10)
box.SetMarginEnd(10)
box.SetMarginTop(10)
box.SetMarginBottom(10)
box.Add(spn)
box.Add(lbl)
win.Add(box)
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
win.ShowAll()
win.Show()
go func(win *gtk.Window, ap appimg) {
defer win.Close()
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
resp, err := check.Get(urlBase + ap.name)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
name := strings.Split(ap.name, "-")[0]
var foldName string
if _, err = os.Open("PortableApps/" + name + "Portable"); err == nil {
foldName = "PortableApps/" + name + "Portable"
} else if _, err = os.Open("PortableApps/" + name); err == nil {
foldName = "PortableApps/" + name
} else {
os.Mkdir("PortableApps/"+name, 0777)
foldName = "PortableApps/" + name
}
fil, err := os.Create(foldName + "/" + ap.name)
if err != nil {
fmt.Println(err)
return
}
io.Copy(fil, resp.Body)
_ = fil.Chmod(0777)
}(win, ap)
}
-112
View File
@@ -1,112 +0,0 @@
//Package appimg is for downloading new AppImages for LinuxPA
package appimg
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
const (
urlBase = "https://dl.bintray.com/probono/AppImages/"
)
//ShowUI shows the list of possible AppImages to be downloaded in a gtk.Window
func ShowUI(clsFunc func()) {
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.Connect("destroy", func() {
clsFunc()
})
apps := make([]appimg, 0)
win.SetSizeRequest(400, 400)
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
appList, _ := gtk.ListBoxNew()
apch := make(chan appimg)
appList.SetHExpand(true)
appList.SetVExpand(true)
vScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
hScrollCat, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
lst, _ := gtk.ScrolledWindowNew(hScrollCat, vScrollCat)
lst.SetSizeRequest(170, 500)
lst.Add(appList)
box.Add(lst)
win.Add(box)
appList.Connect("row-activated", func() {
if appList.GetSelectedRow().GetIndex() >= 0 {
downloadApp(win, apps[appList.GetSelectedRow().GetIndex()])
}
})
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
win.ShowAll()
win.Show()
getList(win, apch)
go func(win *gtk.Window, apch chan appimg, list *gtk.ListBox) {
for i := range apch {
glib.IdleAdd(func(list *gtk.ListBox, i appimg) {
lbl, _ := gtk.LabelNew(i.name)
list.Add(lbl)
apps = append(apps, i)
lbl.Show()
}, list, i)
}
}(win, apch, appList)
}
func getList(parent *gtk.Window, apch chan appimg) {
win, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
win.SetTransientFor(parent)
win.SetDestroyWithParent(true)
win.Connect("destroy", func() {
parent.SetSensitive(true)
})
parent.SetSensitive(false)
spin, _ := gtk.SpinnerNew()
spin.Start()
txt, _ := gtk.LabelNew("Getting List...")
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
box.SetMarginBottom(10)
box.SetMarginEnd(10)
box.SetMarginStart(10)
box.SetMarginTop(10)
box.Add(spin)
box.Add(txt)
win.Add(box)
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
win.ShowAll()
win.Show()
go func(win *gtk.Window, apch chan appimg) {
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
resp, err := check.Get(urlBase)
if err != nil {
fmt.Println(err)
close(apch)
win.Close()
return
}
defer resp.Body.Close()
btys, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
close(apch)
win.Close()
return
}
tgs := convert(string(btys))
for _, v := range tgs {
if strings.HasSuffix(strings.ToLower(v.Meat), ".appimage") {
apch <- newApp(v.Meat)
}
}
close(apch)
win.Close()
}(win, apch)
}
+44
View File
@@ -0,0 +1,44 @@
module github.com/CalebQ42/LinuxPA
go 1.23.1
require github.com/probonopd/go-appimage v0.0.0-20240922191415-5cf876da9cdc
require (
gioui.org v0.7.1 // indirect
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
gioui.org/shader v1.0.8 // indirect
github.com/CalebQ42/squashfs v1.0.2 // indirect
github.com/adrg/xdg v0.5.0 // indirect
github.com/alokmenghrajani/gpgeez v0.0.0-20161206084504-1a06f1c582f9 // indirect
github.com/eclipse/paho.mqtt.golang v1.5.0 // indirect
github.com/emirpasic/gods v1.12.0 // indirect
github.com/go-text/typesetting v0.1.1 // indirect
github.com/google/go-github v17.0.0+incompatible // indirect
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e // indirect
github.com/sergi/go-diff v1.0.0 // indirect
github.com/src-d/gcfg v1.4.0 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/xanzy/ssh-agent v0.2.1 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 // indirect
golang.org/x/image v0.18.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect
gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
+130
View File
@@ -0,0 +1,130 @@
gioui.org v0.7.1 h1:l7OVj47n1z8acaszQ6Wlu+Rxme+HqF3q8b+Fs68+x3w=
gioui.org v0.7.1/go.mod h1:5Kw/q7R1BWc5MKStuTNvhCgSrRqbfHc9Dzfjs4IGgZo=
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
github.com/CalebQ42/squashfs v1.0.2 h1:r1OMSTpacV4GXOWaLwnydEpcrv+yhUSIzrvSGYO74Xg=
github.com/CalebQ42/squashfs v1.0.2/go.mod h1:uhKIQfq2+dgJ+utqCkvVk0t7XuqaNhcotCrqSI0wUuI=
github.com/adrg/xdg v0.5.0 h1:dDaZvhMXatArP1NPHhnfaQUqWBLBsmx1h1HXQdMoFCY=
github.com/adrg/xdg v0.5.0/go.mod h1:dDdY4M4DF9Rjy4kHPeNL+ilVF+p2lK8IdM9/rTSGcI4=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alokmenghrajani/gpgeez v0.0.0-20161206084504-1a06f1c582f9 h1:Zio/mdDEpJDG1yeH9y2Kcb9ATWXkE7WIBkO+IMqRbbM=
github.com/alokmenghrajani/gpgeez v0.0.0-20161206084504-1a06f1c582f9/go.mod h1:u65XFfs2+s//7QVkp5Q1NEZl4zVep2BtubxiSXJERN8=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-text/typesetting v0.1.1 h1:bGAesCuo85nXnEN5LmFMVGAGpGkCPtHrZLi//qD7EJo=
github.com/go-text/typesetting v0.1.1/go.mod h1:d22AnmeKq/on0HNv73UFriMKc4Ez6EqZAofLhAzpSzI=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/probonopd/go-appimage v0.0.0-20240922191415-5cf876da9cdc h1:m+G8q9mghEL9nU4sbdHBP0uFWe7/0k3IqeRIn5TrPnU=
github.com/probonopd/go-appimage v0.0.0-20240922191415-5cf876da9cdc/go.mod h1:WIMiirlWSahyTIR4hOMWhMojo2Xxqtk/bi/YSNyWYDg=
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e h1:dCWirM5F3wMY+cmRda/B1BiPsFtmzXqV9b0hLWtVBMs=
github.com/rasky/go-lzo v0.0.0-20200203143853-96a758eda86e/go.mod h1:9leZcVcItj6m9/CfHY5Em/iBrCz7js8LcRQGTKEEv2M=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw=
github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmGM60GmlIys+zNX63d6/J4CMtU=
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37/go.mod h1:3F+MieQB7dRYLTmnncoFbb1crS5lfQoTfDgQy6K4N0o=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-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 -65
View File
@@ -1,82 +1,42 @@
package main
import (
"encoding/gob"
"fmt"
"os"
"github.com/gotk3/gotk3/gtk"
"gioui.org/app"
"gioui.org/op"
"gioui.org/widget/material"
)
const (
version = "2.1.0.5"
defIni = ""
)
var (
master map[string][]app
linmaster map[string][]app
cats []string
lin []string
wine bool
comEnbld bool
wineAvail bool
version = "3.0.0-alpha1"
)
func main() {
os.MkdirAll("PortableApps/LinuxPACom", 0777)
master = make(map[string][]app)
linmaster = make(map[string][]app)
uiStart()
go func() {
w := &app.Window{}
w.Option(app.Size(500, 500), app.Title("LinuxPA"))
if err := ui(w); err != nil {
fmt.Println(err)
}
os.Exit(0)
}()
app.Main()
}
func uiStart() {
gtk.Init(nil)
setup()
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
if err != nil {
fmt.Println("Window not created", err)
}
win.SetTitle("LinuxPA")
win.Connect("destroy", func() {
savePrefs()
gtk.MainQuit()
})
win.SetDefaultSize(500, 500)
win.SetPosition(gtk.WIN_POS_CENTER)
ui(win)
win.ShowAll()
win.Show()
update(win)
gtk.Main()
}
func savePrefs() {
fil, err := os.Open("PortableApps/LinuxPACom/Prefs.gob")
if os.IsNotExist(err) {
fil, err = os.Create("PortableApps/LinuxPACom/Prefs.gob")
}
if err != nil {
return
}
enc := gob.NewEncoder(fil)
enc.Encode(wine)
}
func loadPrefs() {
fil, err := os.Open("PortableApps/LinuxPACom/Prefs.gob")
if err != nil {
return
}
dec := gob.NewDecoder(fil)
dec.Decode(&wine)
}
func contains(arr []string, str string) bool {
for _, v := range arr {
if v == str {
return true
func ui(w *app.Window) error {
th := material.NewTheme()
op := &op.Ops{}
for {
switch e := w.Event().(type) {
case app.DestroyEvent:
return e.Err
case app.FrameEvent:
ctx := app.NewContext(op, e)
lbl := material.Body1(th, "Hello there!")
lbl.Layout(ctx)
e.Frame(op)
}
}
return false
}
+66
View File
@@ -0,0 +1,66 @@
package main
import (
"errors"
"io"
"net/http"
"os"
"os/exec"
"testing"
)
const (
testImage = "https://darkstorm.tech/files/LinuxPATest.sfs"
)
func setupTestEnv() error {
_, err := exec.LookPath("unsquashfs")
if err != nil {
return errors.New("unsquashfs not installed")
}
fold, err := os.Stat("testing")
if os.IsNotExist(err) {
err = os.Mkdir("testing", 0777)
if err != nil {
return err
}
fold, err = os.Stat("testing")
if err != nil {
return err
}
} else if err != nil {
return err
}
os.RemoveAll("testing/PortableApps")
os.RemoveAll("testing/Documents")
os.RemoveAll("testing/Start.exe")
if !fold.IsDir() {
return errors.New("./testing is not a directory!!!")
}
img, err := os.Open("testing/LinuxPATest.sfs")
if os.IsNotExist(err) {
img, err = os.Create("testing/LinuxPATest.sfs")
if err != nil {
return errors.New("Cannot create testing/LinuxPATest.sfs")
}
resp, err := http.DefaultClient.Get(testImage)
if err != nil {
return err
}
_, err = io.Copy(img, resp.Body)
resp.Body.Close()
if err != nil {
return err
}
}
err = exec.Command("unsquashfs", "-d", "./testing", "./testing/LinuxPATest.sfs").Run()
if err != nil {
return err
}
return nil
}
func TestStuff(t *testing.T) {
setupTestEnv()
main()
}
-108
View File
@@ -1,108 +0,0 @@
package main
import (
"io/ioutil"
"os"
"github.com/gotk3/gotk3/gtk"
)
func settingsUI() {
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.SetDefaultSize(600, 300)
win.SetPosition(gtk.WIN_POS_CENTER)
comTagTbl, _ := gtk.TextTagTableNew()
comBuf, _ := gtk.TextBufferNew(comTagTbl)
ntbk, _ := gtk.NotebookNew()
gnrl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
gnrl.SetMarginStart(10)
gnrl.SetMarginEnd(10)
gnrl.SetMarginTop(10)
gnrl.SetMarginBottom(10)
dlWine, _ := gtk.ButtonNewWithLabel("Download Wine")
wineLbl, _ := gtk.LabelNew("PortableApps/LinuxPACom/Wine present")
gnrl.Add(wineLbl)
dlWine.Connect("clicked", func() {
cb := make(chan bool)
downloadWine(win, cb)
go func() {
v := <-cb
if v {
setupTxt(comBuf)
wineLbl.Show()
}
}()
})
if !comEnbld {
dlWine.SetSensitive(false)
dlWine.SetTooltipText("common.sh needed")
}
gnrl.Add(dlWine)
ntbk.AppendPage(gnrl, getLabel("General"))
com, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
com.SetMarginStart(10)
com.SetMarginEnd(10)
com.SetMarginTop(10)
com.SetMarginBottom(10)
comEdit, _ := gtk.TextViewNewWithBuffer(comBuf)
comEdit.SetVExpand(true)
comEdit.SetHExpand(true)
vScroll, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
hScroll, _ := gtk.AdjustmentNew(0, 0, 0, 0, 0, 0)
comScrl, _ := gtk.ScrolledWindowNew(hScroll, vScroll)
comScrl.Add(comEdit)
com.Add(comScrl)
svBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
sv, _ := gtk.ButtonNewWithLabel("Save")
sv.Connect("clicked", func() {
beg, end := comBuf.GetBounds()
txt, _ := comBuf.GetText(beg, end, true)
ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", []byte(txt), 0777)
})
cnl, _ := gtk.ButtonNewWithLabel("Cancel")
cnl.Connect("clicked", func() {
setupTxt(comBuf)
})
svBox.Add(sv)
svBox.Add(cnl)
com.Add(svBox)
ntbk.AppendPage(com, getLabel("common.sh"))
win.Add(ntbk)
win.ShowAll()
if !comEnbld {
comScrl.Hide()
svBox.Hide()
mkCom, _ := gtk.ButtonNewWithLabel("Create common.sh")
mkCom.Connect("clicked", func() {
err := ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", []byte("export HOME=$PWD/PortableApps/LinuxPACom/Home"), 0777)
if err == nil {
mkCom.Hide()
comScrl.Show()
svBox.Show()
setupTxt(comBuf)
comEnbld = true
dlWine.SetSensitive(true)
dlWine.SetTooltipText("")
}
})
mkCom.Show()
com.Add(mkCom)
} else {
setupTxt(comBuf)
}
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); err != nil && os.IsNotExist(err) {
wineLbl.Hide()
}
win.Show()
}
func setupTxt(buf *gtk.TextBuffer) {
fil, _ := os.Open("PortableApps/LinuxPACom/common.sh")
btys, _ := ioutil.ReadAll(fil)
buf.SetText(string(btys))
}
func getLabel(name string) *gtk.Label {
lbl, _ := gtk.LabelNew(name)
return lbl
}
-196
View File
@@ -1,196 +0,0 @@
package main
import (
"bufio"
_ "image/png"
"os"
"os/exec"
"reflect"
"sort"
"strings"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)
func setup() {
loadPrefs()
if _, err := os.Open("PortableApps/LinuxPACom/Wine"); os.IsNotExist(err) {
if _, errd := exec.LookPath("wine"); errd == nil {
wineAvail = true
}
} else if err == nil {
wineAvail = true
}
if !wineAvail {
wine = false
}
PortableAppsFold, err := os.Open("PortableApps")
if PAStat, _ := PortableAppsFold.Stat(); err != nil || !PAStat.IsDir() {
os.Mkdir("PortableApps", 0777)
PortableAppsFold, err = os.Open("PortableApps")
if err != nil {
panic("Can't find PortableApps folder and can't create one!")
}
}
if _, err = os.Open("PortableApps/LinuxPACom"); err != nil {
os.Mkdir("PortableApps/LinuxPACom", 0777)
}
_, err = os.Open("PortableApps/LinuxPACom/common.sh")
if err == nil {
comEnbld = true
}
PAFolds, _ := PortableAppsFold.Readdirnames(-1)
sort.Strings(PAFolds)
for _, v := range PAFolds {
fold, _ := os.Open("PortableApps/" + v)
if stat, _ := fold.Stat(); stat.IsDir() && stat.Name() != "PortableApps.com" && stat.Name() != "LinuxPACom" {
ap := processApp("PortableApps/" + v)
if !reflect.DeepEqual(ap, app{}) {
if _, ok := master[ap.cat]; !ok {
cats = append(cats, ap.cat)
sort.Strings(cats)
}
if len(ap.lin) != 0 {
if _, ok := linmaster[ap.cat]; !ok {
lin = append(lin, ap.cat)
sort.Strings(lin)
}
}
master[ap.cat] = append(master[ap.cat], ap)
if len(ap.lin) != 0 {
linmaster[ap.cat] = append(linmaster[ap.cat], ap)
}
}
}
}
}
func processApp(fold string) (out app) {
wd, _ := os.Getwd()
out.dir = wd + "/" + fold
out.ini = findInfo(fold)
if out.ini != nil {
out.name = getName(out.ini)
out.ini = findInfo(fold)
out.cat = getCat(out.ini)
out.ini = findInfo(fold)
}
if out.name == "" {
out.name = strings.TrimPrefix(fold, "PortableApps/")
}
if out.cat == "" {
out.cat = "Other"
}
out.icon = getIcon(fold)
folder, _ := os.Open(fold)
fis, _ := folder.Readdirnames(-1)
for _, v := range fis {
tmp, _ := os.Open(fold + "/" + v)
if stat, _ := tmp.Stat(); stat.IsDir() {
continue
}
if strings.HasSuffix(strings.ToLower(v), ".appimage") {
out.appimg = append(out.appimg, v)
out.ex = append(out.ex, v)
out.lin = append(out.lin, v)
} else if strings.HasSuffix(strings.ToLower(v), ".exe") {
out.ex = append(out.ex, v)
} else {
btys := make([]byte, 4)
rdr := bufio.NewReader(tmp)
rdr.Read(btys)
if (strings.Contains(strings.ToLower(string(btys)), "elf") && !strings.HasSuffix(strings.ToLower(v), ".so") && !strings.Contains(v, ".so.")) || strings.HasPrefix(strings.ToLower(string(btys)), "#!") {
out.ex = append(out.ex, v)
out.lin = append(out.lin, v)
}
}
}
if len(out.ex) == 0 {
return app{}
}
if len(out.lin) == 0 {
out.name += " (Wine)"
}
return
}
func getCat(ini *os.File) string {
rdr := bufio.NewReader(ini)
var ret string
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
if strings.HasPrefix(string(line), "Category=") {
ret = strings.TrimPrefix(string(line), "Category=")
break
} else if strings.HasPrefix(string(line), "category=") {
ret = strings.TrimPrefix(string(line), "category=")
}
}
rdr.Reset(ini)
return ret
}
func getName(ini *os.File) string {
rdr := bufio.NewReader(ini)
var ret string
for line, _, err := rdr.ReadLine(); err == nil; line, _, err = rdr.ReadLine() {
if strings.HasPrefix(string(line), "Name=") {
ret = strings.TrimPrefix(string(line), "Name=")
break
} else if strings.HasPrefix(string(line), "name=") {
ret = strings.TrimPrefix(string(line), "name=")
break
}
}
rdr.Reset(ini)
return ret
}
func getIcon(fold string) *gdk.Pixbuf {
var pic string
if _, err := os.Open(fold + "/appicon.png"); err == nil {
pic = fold + "/appicon.png"
} else if folder, err := os.Open(fold + "/App/AppInfo"); err == nil {
fis, _ := folder.Readdir(-1)
var pics []string
for _, v := range fis {
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".png") && strings.HasPrefix(strings.ToLower(v.Name()), "appicon_") {
pics = append(pics, v.Name())
}
}
sort.Strings(pics)
if len(pics) > 1 {
var ind int
if !contains(pics, "appicon_32.png") {
ind = len(pics) - 1
} else {
ind = sort.SearchStrings(pics, "appicon_32.png")
}
pic = fold + "/App/AppInfo/" + pics[ind]
}
} else {
img, _ := gtk.ImageNewFromIconName("application-x-executable", gtk.ICON_SIZE_BUTTON)
buf := img.GetPixbuf()
return buf
}
img, _ := gtk.ImageNewFromFile(pic)
buf, _ := img.GetPixbuf().ScaleSimple(32, 32, gdk.INTERP_BILINEAR)
return buf
}
func findInfo(fold string) *os.File {
if fi, err := os.Open(fold + "/appinfo.ini"); err == nil {
return fi
}
tmp, err := os.Open(fold + "/App/AppInfo")
if err == nil {
fis, _ := tmp.Readdirnames(-1)
for _, v := range fis {
if strings.ToLower(v) == "appinfo.ini" {
tmp, _ := os.Open(fold + "/App/AppInfo/" + v)
return tmp
}
}
}
return nil
}
-197
View File
@@ -1,197 +0,0 @@
package main
import (
"github.com/CalebQ42/LinuxPA/appimg"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
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() {
settingsUI()
})
settings.SetTooltipText("Settings")
dnl, _ := gtk.ButtonNewFromIconName("emblem-downloads", gtk.ICON_SIZE_SMALL_TOOLBAR)
dnl.SetTooltipText("Download Apps")
header.PackStart(settings)
header.PackEnd(dnl)
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)
appsList.SetHeadersVisible(false)
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)
catScrl.SetSizeRequest(170, 500)
appScrl, _ := gtk.ScrolledWindowNew(hScrollApp, vScrollApp)
appScrl.Add(appsList)
appScrl.SetSizeRequest(300, 500)
lrBox.Add(catScrl)
lrBox.Add(appScrl)
botBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 2)
botBox.SetMarginStart(10)
botBox.SetMarginEnd(10)
botBox.SetMarginTop(10)
botBox.SetMarginBottom(10)
wineCheck, _ := gtk.CheckButtonNewWithLabel("Show Windows apps (Wine)")
if !wineAvail {
wineCheck.SetSensitive(false)
wineCheck.SetTooltipText("Download wine to run windows apps")
}
wineCheck.SetActive(wine)
wineCheck.Connect("toggled", func() {
wine = wineCheck.GetActive()
store.Clear()
for i := range ls {
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
}
ls = getCatRows()
for _, v := range ls {
catList.Add(v)
}
catList.ShowAll()
})
edit, _ := gtk.ButtonNewWithLabel("Edit App..")
edit.Connect("clicked", func() {
selec, _ := appsList.GetSelection()
_, it, ok := selec.GetSelected()
if ok {
pth, _ := store.GetPath(it)
ind := pth.GetIndices()
if wine {
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
appLnch.edit(win, func() {
store.Clear()
for i := range ls {
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
}
ls = getCatRows()
for i, v := range ls {
catList.Insert(v, i)
}
catList.ShowAll()
})
} else {
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
appLnch.edit(win, func() {
store.Clear()
for i := range ls {
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
}
ls = getCatRows()
for i, v := range ls {
catList.Insert(v, i)
}
catList.ShowAll()
})
}
}
})
botBox.Add(wineCheck)
botBox.PackEnd(edit, false, false, 0)
topLvl.Add(lrBox)
topLvl.PackEnd(botBox, false, true, 0)
win.Add(topLvl)
for _, v := range ls {
catList.Add(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 {
apps := linmaster[lin[catList.GetSelectedRow().GetIndex()]]
for _, v := range apps {
treeApps = append(treeApps, v.getTreeIter(store))
}
}
}
})
appsList.Connect("row-activated", func() {
selec, _ := appsList.GetSelection()
_, it, ok := selec.GetSelected()
if ok {
pth, _ := store.GetPath(it)
ind := pth.GetIndices()
if len(ind) == 1 {
if wine {
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
appLnch.launch()
} else {
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
appLnch.launch()
}
} else if len(ind) == 2 {
if wine {
appLnch := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
appLnch.launchSub(ind[1])
} else {
appLnch := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
appLnch.launchSub(ind[1])
}
}
}
})
dnl.Connect("clicked", func() {
appimg.ShowUI(func() {
master = make(map[string][]app)
linmaster = make(map[string][]app)
cats = make([]string, 0)
lin = make([]string, 0)
setup()
store.Clear()
for i := range ls {
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
}
ls = getCatRows()
for i, v := range ls {
catList.Insert(v, i)
}
catList.ShowAll()
})
})
}
func getCatRows() (out []*gtk.Label) {
if wine {
for _, v := range cats {
txt, _ := gtk.LabelNew(v)
out = append(out, txt)
}
} else {
for _, v := range lin {
txt, _ := gtk.LabelNew(v)
out = append(out, txt)
}
}
return
}
-156
View File
@@ -1,156 +0,0 @@
package main
import (
"bufio"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"strconv"
"strings"
"github.com/gotk3/gotk3/gtk"
)
const (
versionURL = "https://www.dropbox.com/s/a0xizzo0a4vsfqt/Version?dl=1"
downloadURL = "https://github.com/CalebQ42/LinuxPA/releases/download/vXXX/LinuxPA"
)
//Thanks to https://www.socketloop.com/tutorials/golang-download-file-example
//For some of the code
//Returns if success
func versionDL() (bool, error) {
versionFile, err := os.Create("PortableApps/LinuxPACom/Version")
if err != nil {
return false, err
}
versionFile.Chmod(0777)
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
response, err := check.Get(versionURL)
if err != nil {
return false, err
}
_, err = io.Copy(versionFile, response.Body)
if err != nil {
return false, err
}
return true, nil
}
func getVersionFileInfo() string {
fil, err := os.Open("PortableApps/LinuxPACom/Version")
if err != nil {
return "Error!"
}
rdr := bufio.NewReader(fil)
out, _, _ := rdr.ReadLine()
return string(out)
}
func checkForUpdate(new string) (bool, error) {
curSlice := strings.Split(version, ".")
newSlice := strings.Split(new, ".")
curNums := make([]int, 4)
newNums := make([]int, 4)
for i, v := range curSlice {
num, err := strconv.Atoi(v)
if err == nil {
curNums[i] = num
}
num, err = strconv.Atoi(newSlice[i])
if err == nil {
newNums[i] = num
} else {
return false, err
}
if newNums[i] > curNums[i] {
return true, nil
} else if curNums[i] > newNums[i] {
return false, nil
}
}
return false, nil
}
func downloadUpdate(newVersion string) (bool, error) {
url := strings.Replace(downloadURL, "XXX", newVersion, -1)
err := os.Rename("LinuxPA", ".LinuxPA.old")
if err != nil {
return false, err
}
fil, err := os.Create("LinuxPA")
fil.Chmod(0777)
defer fil.Close()
if err != nil {
os.Rename(".LinuxPA.old", "LinuxPA")
return false, err
}
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
re, err := check.Get(url)
if err != nil {
return false, err
}
defer re.Body.Close()
_, err = io.Copy(fil, re.Body)
if err != nil {
return false, err
}
return true, nil
}
func update(win *gtk.Window) {
updateWin, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
updateWin.SetTransientFor(win)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
spin, _ := gtk.SpinnerNew()
spin.Start()
lbl, _ := gtk.LabelNew("Checking for updates")
topLvl.Add(spin)
topLvl.Add(lbl)
topLvl.SetMarginBottom(10)
topLvl.SetMarginEnd(10)
topLvl.SetMarginStart(10)
topLvl.SetMarginTop(10)
updateWin.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
updateWin.Add(topLvl)
updateWin.ShowAll()
updateWin.Show()
go func(win, updateWin *gtk.Window) {
defer updateWin.Close()
stat, err := versionDL()
if stat {
res := getVersionFileInfo()
if res != "Error!" {
stat, err = checkForUpdate(res)
if stat {
lbl.SetText("Updating!")
downloadUpdate(res)
win.Close()
cmd := exec.Command("./LinuxPA")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Start()
} else {
fmt.Println(err)
}
} else {
fmt.Println("Failed Version File Info")
}
} else {
fmt.Println(err)
}
}(win, updateWin)
}
-101
View File
@@ -1,101 +0,0 @@
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/gotk3/gotk3/gtk"
"github.com/mholt/archiver"
)
const (
wineURL = "https://www.playonlinux.com/wine/binaries/linux-amd64/PlayOnLinux-wine-2.5-linux-amd64.pol"
)
func downloadWine(parent *gtk.Window, cb chan bool) {
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.SetTransientFor(parent)
win.SetDestroyWithParent(true)
win.Connect("destroy", func() {
parent.SetSensitive(true)
})
parent.SetSensitive(false)
spin, _ := gtk.SpinnerNew()
spin.Start()
txt, _ := gtk.LabelNew("Downloading Wine")
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
box.SetMarginBottom(10)
box.SetMarginEnd(10)
box.SetMarginStart(10)
box.SetMarginTop(10)
box.Add(spin)
box.Add(txt)
win.Add(box)
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
win.ShowAll()
win.Show()
go func(win *gtk.Window, txt *gtk.Label) {
defer win.Close()
wineTar, err := os.Create("PortableApps/LinuxPACom/wine2.5.tar.bz2")
if err != nil {
fmt.Println(err)
cb <- false
return
}
defer wineTar.Close()
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
resp, err := check.Get(wineURL)
if err != nil {
fmt.Println(err)
cb <- false
return
}
os.RemoveAll("PortableApps/LinuxPACom/Wine")
defer resp.Body.Close()
_, err = io.Copy(wineTar, resp.Body)
if err != nil {
fmt.Println(err)
cb <- false
return
}
txt.SetText("Extracting Wine")
err = archiver.TarBz2.Open("PortableApps/LinuxPACom/wine2.5.tar.bz2", "PortableApps/LinuxPACom/Wine")
if err != nil {
fmt.Println(err)
cb <- false
return
}
fil, err := os.Open("PortableApps/LinuxPACom/common.sh")
if err != nil {
fmt.Println(err)
cb <- false
return
}
tmp, err := ioutil.ReadAll(fil)
if err != nil {
fmt.Println(err)
cb <- false
return
}
if !strings.Contains(string(tmp), "export PATH=$PWD/PortableApps/LinuxPACom/Wine/wineversion/2.5/bin:$PATH") {
tmp = append(tmp, []byte("\nexport PATH=$PWD/PortableApps/LinuxPACom/Wine/wineversion/2.5/bin:$PATH")...)
ioutil.WriteFile("PortableApps/LinuxPACom/common.sh", tmp, 0777)
if err != nil {
fmt.Println(err)
cb <- false
return
}
}
cb <- true
return
}(win, txt)
}