Compare commits
36 Commits
v2.1.0.0
...
raylib-exp
| Author | SHA1 | Date | |
|---|---|---|---|
| 50105c242a | |||
| 6e8d97f29b | |||
| c8e0f08aae | |||
| 916f9cc79b | |||
| e4e5adaf13 | |||
| 7a2ebd533e | |||
| 2f0ca5418c | |||
| ce9d4aed23 | |||
| 712a5ab33d | |||
| 6723f933b4 | |||
| 016fc35745 | |||
| ba5e3510ec | |||
| 7e2d7ee14b | |||
| b20de4f1d6 | |||
| d2e91baa6b | |||
| a0f22e480b | |||
| 57f921c2cb | |||
| 55f897db46 | |||
| 3d9583281e | |||
| ec4d66f6b2 | |||
| c442ef5688 | |||
| 78d3723bf4 | |||
| 828b9f4cda | |||
| be64aa083f | |||
| 3111705cae | |||
| 868ae8f700 | |||
| 226e9d6210 | |||
| 56748f043e | |||
| 3d3239fe0a | |||
| 6e643b68ac | |||
| 539f33d25e | |||
| 4d3cb9f486 | |||
| a55c82483a | |||
| 9e9bb82025 | |||
| ea91d3cd80 | |||
| 2a0d53db09 |
@@ -0,0 +1 @@
|
||||
testing/
|
||||
@@ -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.
|
||||
|
||||
# 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.
|
||||
## 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 Website](http://appimage.org)
|
||||
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
|
||||
|
||||
# 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.
|
||||
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6). The screenshots are with the adapta gtk theme
|
||||
|
||||
## TODO (Might be in order)
|
||||
|
||||
1. MAKE IT BETTER
|
||||
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
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/gotk3/gotk3/gdk"
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
type app struct {
|
||||
name string
|
||||
cat string
|
||||
appimg []string
|
||||
lin []string
|
||||
ex []string
|
||||
icon *gdk.Pixbuf
|
||||
dir string
|
||||
ini *os.File
|
||||
}
|
||||
|
||||
func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter {
|
||||
it := store.Append(nil)
|
||||
store.SetValue(it, 0, a.icon)
|
||||
store.SetValue(it, 1, a.name)
|
||||
if len(a.ex) > 1 {
|
||||
if wine {
|
||||
for _, v := range a.ex {
|
||||
i := store.Append(it)
|
||||
store.SetValue(i, 1, v)
|
||||
}
|
||||
} else {
|
||||
for _, v := range a.lin {
|
||||
i := store.Append(it)
|
||||
store.SetValue(i, 1, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
func (a *app) launch() {
|
||||
if len(a.ex) == 1 {
|
||||
if wine {
|
||||
var cmd *exec.Cmd
|
||||
if !contains(a.lin, a.ex[0]) {
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||
}
|
||||
} else {
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||
}
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
} else {
|
||||
var cmd *exec.Cmd
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
}
|
||||
} else {
|
||||
if wine {
|
||||
var cmd *exec.Cmd
|
||||
if len(a.lin) == 0 {
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
|
||||
}
|
||||
} else {
|
||||
var ind int
|
||||
for i, v := range a.lin {
|
||||
if strings.HasSuffix(v, ".sh") {
|
||||
ind = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||
}
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
} else {
|
||||
if len(a.lin) != 0 {
|
||||
var ind int
|
||||
for i, v := range a.lin {
|
||||
if strings.HasSuffix(v, ".sh") {
|
||||
ind = i
|
||||
break
|
||||
}
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *app) launchSub(sub int) {
|
||||
if wine {
|
||||
var cmd *exec.Cmd
|
||||
if !contains(a.lin, a.ex[sub]) {
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
|
||||
}
|
||||
} else {
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||
}
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
} else {
|
||||
var cmd *exec.Cmd
|
||||
if comEnbld {
|
||||
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||
} else {
|
||||
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Start()
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package appimg
|
||||
|
||||
type appimg struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func newApp(name string) appimg {
|
||||
var out appimg
|
||||
out.name = name
|
||||
return out
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
module github.com/CalebQ42/LinuxPA
|
||||
|
||||
go 1.23.1
|
||||
|
||||
require github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b
|
||||
|
||||
require (
|
||||
github.com/ebitengine/purego v0.8.2 // indirect
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b h1:JJfspevP3YOXcSKVABizYOv++yMpTJIdPUtoDzF/RWw=
|
||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"time"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
// A rectangle with borders.
|
||||
// Default only has black borders.
|
||||
type Rect struct {
|
||||
x int32
|
||||
y int32
|
||||
h int32
|
||||
w int32
|
||||
radius int32
|
||||
reload bool
|
||||
shown bool
|
||||
rendering bool
|
||||
|
||||
borderWidth int32
|
||||
borderColor color.RGBA
|
||||
fillColor color.RGBA
|
||||
|
||||
curTweens map[string]*Tween
|
||||
tex rl.RenderTexture2D
|
||||
}
|
||||
|
||||
func NewRect(x, y, height, width int32) *Rect {
|
||||
r := &Rect{
|
||||
x: x,
|
||||
y: y,
|
||||
h: height,
|
||||
w: width,
|
||||
radius: 0,
|
||||
borderWidth: 2,
|
||||
borderColor: rl.Black,
|
||||
fillColor: rl.Blank,
|
||||
reload: true,
|
||||
curTweens: make(map[string]*Tween),
|
||||
}
|
||||
r.tex = rl.LoadRenderTexture(width, height)
|
||||
rl.SetTextureFilter(r.tex.Texture, rl.FilterAnisotropic8x|rl.FilterBilinear)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *Rect) Copy() *Rect {
|
||||
return &Rect{
|
||||
x: r.x,
|
||||
y: r.y,
|
||||
h: r.h,
|
||||
w: r.w,
|
||||
radius: r.radius,
|
||||
borderWidth: r.borderWidth,
|
||||
borderColor: r.borderColor,
|
||||
fillColor: r.fillColor,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) addTween(key string, old, new int32) {
|
||||
r.curTweens[key] = NewTween(old, new, 1000*time.Millisecond)
|
||||
}
|
||||
|
||||
func (r *Rect) SetPosition(x, y int32) {
|
||||
if !r.shown {
|
||||
r.x, r.y = x, y
|
||||
return
|
||||
}
|
||||
if r.x != x {
|
||||
r.addTween("x", r.x, x)
|
||||
}
|
||||
if r.y != y {
|
||||
r.addTween("y", r.y, y)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetSize(h, w int32) {
|
||||
if !r.shown {
|
||||
r.h, r.w = h, w
|
||||
return
|
||||
}
|
||||
if r.h != h {
|
||||
r.addTween("h", r.h, h)
|
||||
r.reload = true
|
||||
}
|
||||
if r.w != w {
|
||||
r.addTween("w", r.w, w)
|
||||
r.reload = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetBorderRadius(radius int32) {
|
||||
if !r.shown {
|
||||
r.radius = radius
|
||||
return
|
||||
}
|
||||
if r.radius != radius {
|
||||
r.addTween("radius", r.radius, radius)
|
||||
r.reload = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetBorderWidth(w int32) {
|
||||
if !r.shown {
|
||||
r.borderWidth = w
|
||||
return
|
||||
}
|
||||
if r.borderWidth != w {
|
||||
r.addTween("borderWidth", r.borderWidth, w)
|
||||
r.reload = true
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Rect) SetBorderColor(c color.RGBA) {
|
||||
if r.borderColor != c {
|
||||
r.reload = true
|
||||
}
|
||||
r.borderColor = c
|
||||
}
|
||||
|
||||
func (r *Rect) SetFillColor(c color.RGBA) {
|
||||
if r.fillColor != c {
|
||||
r.reload = true
|
||||
}
|
||||
r.fillColor = c
|
||||
}
|
||||
|
||||
func (r *Rect) Draw() {
|
||||
r.shown = true
|
||||
if !r.reload && len(r.curTweens) == 0 {
|
||||
rl.DrawTextureEx(r.tex.Texture, rl.NewVector2(float32(r.x), float32(r.y)), 0, 1, rl.White)
|
||||
return
|
||||
}
|
||||
var curRect *Rect
|
||||
updateTex := false
|
||||
if len(r.curTweens) != 0 {
|
||||
curRect = r.Copy()
|
||||
tween, ok := r.curTweens["x"]
|
||||
if ok {
|
||||
curRect.x = tween.CurVal()
|
||||
if tween.Ended() {
|
||||
r.x = curRect.x
|
||||
delete(r.curTweens, "x")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["y"]
|
||||
if ok {
|
||||
curRect.y = tween.CurVal()
|
||||
if tween.Ended() {
|
||||
r.y = curRect.y
|
||||
delete(r.curTweens, "y")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["h"]
|
||||
if ok {
|
||||
curRect.h = tween.CurVal()
|
||||
if curRect.h != r.h {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.h = curRect.h
|
||||
delete(r.curTweens, "h")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["w"]
|
||||
if ok {
|
||||
curRect.w = tween.CurVal()
|
||||
if curRect.w != r.w {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.w = curRect.w
|
||||
delete(r.curTweens, "w")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["radius"]
|
||||
if ok {
|
||||
curRect.radius = tween.CurVal()
|
||||
if curRect.radius != r.radius {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.radius = curRect.radius
|
||||
delete(r.curTweens, "radius")
|
||||
}
|
||||
}
|
||||
tween, ok = r.curTweens["borderWidth"]
|
||||
if ok {
|
||||
curRect.borderWidth = tween.CurVal()
|
||||
if curRect.borderWidth != r.borderWidth {
|
||||
updateTex = true
|
||||
}
|
||||
if tween.Ended() {
|
||||
r.borderWidth = curRect.borderWidth
|
||||
delete(r.curTweens, "borderWidth")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
curRect = r
|
||||
}
|
||||
if r.reload || updateTex {
|
||||
// rl.UnloadTexture(r.tex)
|
||||
// r.tex = rl.LoadTextureFromImage(curRect.buildImage())
|
||||
// rl.UpdateTexture(r.tex, rl.LoadImageColors(curRect.buildImage()))
|
||||
rl.BeginTextureMode(r.tex)
|
||||
curRect.drawTexture()
|
||||
rl.EndTextureMode()
|
||||
}
|
||||
rl.DrawTexturePro(r.tex.Texture, rl.NewRectangle(0, 0, float32(curRect.w), float32(curRect.h)), rl.NewRectangle(float32(curRect.x), float32(curRect.y), float32(curRect.w), float32(curRect.h)), rl.NewVector2(0, 0), 0, rl.White)
|
||||
// rl.DrawTextureEx(r.tex.Texture, rl.NewVector2(float32(curRect.x), float32(curRect.y)), 0, 1, rl.White)
|
||||
r.reload = false
|
||||
}
|
||||
|
||||
func (r Rect) drawTexture() {
|
||||
rl.ClearBackground(rl.Blank)
|
||||
// Filled areas
|
||||
if r.fillColor != rl.Blank {
|
||||
rl.DrawRectangle(r.radius, 0, (r.w - (2 * r.radius)), r.h, r.fillColor)
|
||||
if r.radius > 0 {
|
||||
rl.DrawRectangle((r.w - r.radius), r.radius, r.radius, (r.h - (2 * r.radius)), r.fillColor)
|
||||
rl.DrawRectangle(0, r.radius, r.radius, (r.h - (2 * r.radius)), r.fillColor)
|
||||
}
|
||||
}
|
||||
|
||||
if r.borderColor != rl.Blank {
|
||||
// Horizontal lines
|
||||
rl.DrawRectangle(r.radius, 0, (r.w - (2 * r.radius)), r.borderWidth, r.borderColor)
|
||||
rl.DrawRectangle(r.radius, (r.h)-(r.borderWidth), (r.w - (2 * r.radius)), r.borderWidth, r.borderColor)
|
||||
// Vertical lines
|
||||
rl.DrawRectangle(0, r.radius, r.borderWidth, (r.h - (2 * r.radius)), r.borderColor)
|
||||
rl.DrawRectangle((r.w)-(r.borderWidth), r.radius, r.borderWidth, (r.h - (2 * r.radius)), r.borderColor)
|
||||
}
|
||||
if r.radius > 0 {
|
||||
r.placeCorners()
|
||||
}
|
||||
}
|
||||
|
||||
func (r Rect) placeCorners() {
|
||||
//bl
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 180, 270, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), 180, 270, 20, r.fillColor)
|
||||
//tl
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 90, 180, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), 90, 180, 20, r.fillColor)
|
||||
//tr
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.w-r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 0, 90, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.w-r.radius), float32(r.h-r.radius)), float32(r.radius-r.borderWidth), 0, 90, 20, r.fillColor)
|
||||
//br
|
||||
if r.borderWidth > 0 {
|
||||
rl.DrawRing(rl.NewVector2(float32(r.w-r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), float32(r.radius), 270, 360, 20, r.borderColor)
|
||||
}
|
||||
rl.DrawCircleSector(rl.NewVector2(float32(r.w-r.radius), float32(r.radius)), float32(r.radius-r.borderWidth), 270, 360, 20, r.fillColor)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
rl "github.com/gen2brain/raylib-go/raylib"
|
||||
)
|
||||
|
||||
type Window struct{}
|
||||
|
||||
func Test() {
|
||||
rl.SetConfigFlags(rl.FlagWindowResizable | rl.FlagWindowHighdpi | rl.FlagVsyncHint | rl.FlagMsaa4xHint)
|
||||
rl.InitWindow(800, 450, "raylib [core] example - basic window")
|
||||
defer rl.CloseWindow()
|
||||
rl.SetTargetFPS(60)
|
||||
|
||||
noto := rl.LoadFont("./noto-sans.ttf")
|
||||
txtImg := rl.ImageTextEx(noto, "Hello World!", 50, 0, rl.Black)
|
||||
txt := rl.LoadTextureFromImage(txtImg)
|
||||
|
||||
tmpRect := NewRect(10, 10, 250, 500)
|
||||
tmpRect.SetBorderRadius(25)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(5 * time.Second)
|
||||
// tmpRect.SetBorderRadius(0)
|
||||
// tmpRect.SetPosition(100, 100)
|
||||
tmpRect.SetSize(400, 700)
|
||||
time.Sleep(5 * time.Second)
|
||||
// tmpRect.SetBorderRadius(25)
|
||||
// tmpRect.SetPosition(10, 10)
|
||||
tmpRect.SetSize(250, 500)
|
||||
}
|
||||
}()
|
||||
// tmpRect.SetFillColor(rl.Green)
|
||||
for !rl.WindowShouldClose() {
|
||||
rl.BeginDrawing()
|
||||
rl.DrawFPS(0, 0)
|
||||
|
||||
rl.ClearBackground(rl.DarkGray)
|
||||
// rl.DrawText("Congrats! You created your first window!", 190, 100, 20, rl.LightGray)
|
||||
// // rl.DrawTextEx(noto, "Congrats! You created your first window!", rl.NewVector2(190, 200), 48, 0, rl.Black)
|
||||
tmpRect.Draw()
|
||||
rl.DrawTexture(txt, 50, 50, rl.Black)
|
||||
rl.EndDrawing()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Tween struct {
|
||||
startVal int32
|
||||
startTime time.Time
|
||||
dif int32
|
||||
dur time.Duration
|
||||
}
|
||||
|
||||
func NewTween(startVal, endVal int32, duration time.Duration) *Tween {
|
||||
return &Tween{
|
||||
startVal: startVal,
|
||||
dif: endVal - startVal,
|
||||
dur: duration,
|
||||
startTime: time.Now().Round(time.Millisecond),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tween) CurVal() int32 {
|
||||
since := time.Now().Round(time.Millisecond).Sub(t.startTime)
|
||||
if since <= 0 {
|
||||
return t.startVal
|
||||
}
|
||||
if since >= t.dur {
|
||||
return t.startVal + t.dif
|
||||
}
|
||||
m := float32(since.Milliseconds()) / float32(t.dur.Milliseconds())
|
||||
m = -1 * float32(math.Log10(-.9*float64(m)+1))
|
||||
return t.startVal + int32(math.Round(float64(float32(t.dif)*m)))
|
||||
}
|
||||
|
||||
func (t *Tween) Ended() bool {
|
||||
return time.Now().Round(time.Millisecond).Sub(t.startTime) >= t.dur
|
||||
}
|
||||
@@ -1,84 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/gotk3/gotk3/gtk"
|
||||
)
|
||||
|
||||
const (
|
||||
version = "2.0.1.0"
|
||||
defIni = ""
|
||||
)
|
||||
|
||||
var (
|
||||
master map[string][]app
|
||||
linmaster map[string][]app
|
||||
cats []string
|
||||
lin []string
|
||||
wine bool
|
||||
comEnbld bool
|
||||
wineAvail bool
|
||||
)
|
||||
import "github.com/CalebQ42/LinuxPA/internal/ui"
|
||||
|
||||
func main() {
|
||||
runtime.GOMAXPROCS(4)
|
||||
os.MkdirAll("PortableApps/LinuxPACom", 0777)
|
||||
master = make(map[string][]app)
|
||||
linmaster = make(map[string][]app)
|
||||
uiStart()
|
||||
}
|
||||
|
||||
func uiStart() {
|
||||
gtk.Init(nil)
|
||||
setup()
|
||||
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
}
|
||||
return false
|
||||
ui.Test()
|
||||
}
|
||||
|
||||
Binary file not shown.
-108
@@ -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
|
||||
}
|
||||
@@ -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 folder, err := os.Open(fold + "/App/AppInfo"); err == nil {
|
||||
fis, _ := folder.Readdir(-1)
|
||||
var pics []string
|
||||
for _, v := range fis {
|
||||
if !v.IsDir() && strings.HasSuffix(strings.ToLower(v.Name()), ".png") && strings.HasPrefix(strings.ToLower(v.Name()), "appicon_") {
|
||||
pics = append(pics, v.Name())
|
||||
}
|
||||
}
|
||||
sort.Strings(pics)
|
||||
if len(pics) > 1 {
|
||||
var ind int
|
||||
if !contains(pics, "appicon_32.png") {
|
||||
ind = len(pics) - 1
|
||||
} else {
|
||||
ind = sort.SearchStrings(pics, "appicon_32.png")
|
||||
}
|
||||
pic = fold + "/App/AppInfo/" + pics[ind]
|
||||
}
|
||||
} else if _, err := os.Open(fold + "/appicon.png"); err == nil {
|
||||
pic = fold + "/appicon.png"
|
||||
} else {
|
||||
img, _ := gtk.ImageNewFromIconName("application-x-executable", gtk.ICON_SIZE_BUTTON)
|
||||
buf := img.GetPixbuf()
|
||||
return buf
|
||||
}
|
||||
img, _ := gtk.ImageNewFromFile(pic)
|
||||
buf, _ := img.GetPixbuf().ScaleSimple(32, 32, gdk.INTERP_BILINEAR)
|
||||
return buf
|
||||
}
|
||||
|
||||
func findInfo(fold string) *os.File {
|
||||
tmp, err := os.Open(fold + "/App/AppInfo")
|
||||
if err == nil {
|
||||
fis, _ := tmp.Readdirnames(-1)
|
||||
for _, v := range fis {
|
||||
if strings.ToLower(v) == "appinfo.ini" {
|
||||
tmp, _ := os.Open(fold + "/App/AppInfo/" + v)
|
||||
return tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
if fi, err := os.Open(fold + "/appinfo.ini"); err == nil {
|
||||
return fi
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"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)
|
||||
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()
|
||||
for i := range ls {
|
||||
fmt.Println(len(ls) - i)
|
||||
catList.Remove(catList.GetRowAtIndex(len(ls) - i - 1))
|
||||
}
|
||||
ls = getCatRows()
|
||||
for _, v := range ls {
|
||||
catList.Add(v)
|
||||
}
|
||||
catList.ShowAll()
|
||||
})
|
||||
botBox.Add(wineCheck)
|
||||
topLvl.Add(lrBox)
|
||||
topLvl.PackEnd(botBox, false, true, 0)
|
||||
win.Add(topLvl)
|
||||
for _, v := range ls {
|
||||
catList.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 {
|
||||
app := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||
app.launch()
|
||||
} else {
|
||||
app := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||
app.launch()
|
||||
}
|
||||
} else if len(ind) == 2 {
|
||||
if wine {
|
||||
app := master[cats[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||
app.launchSub(ind[1])
|
||||
} else {
|
||||
app := linmaster[lin[catList.GetSelectedRow().GetIndex()]][ind[0]]
|
||||
app.launchSub(ind[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
dnl.Connect("clicked", func() {
|
||||
appimg.ShowUI(func() {
|
||||
store.Clear()
|
||||
ls = getCatRows()
|
||||
for _, v := range ls {
|
||||
catList.Add(v)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user