35 Commits

Author SHA1 Message Date
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
Belac Darkstorm ea91d3cd80 Bumping version number 2017-04-11 00:18:23 -05:00
Belac Darkstorm 2a0d53db09 Edit and some bugs 2017-04-11 00:18:00 -05:00
Belac Darkstorm a0213d1886 Finished up downloading 2017-04-09 01:44:02 -05:00
Belac Darkstorm 695ce815d9 Nearly done with download :) 2017-04-09 01:26:31 -05:00
Belac Darkstorm 01556c1eb0 Getting ready for AppImage downloading 2017-04-08 20:06:50 -05:00
Belac Darkstorm d7410bb88f Got things back to normal with a couple bug fixes 2017-04-06 09:26:21 -05:00
Belac Darkstorm bc63e6d10f Revert "Tried some stuff that I didn't like"
This reverts commit 78c6842fab.
2017-04-06 09:23:10 -05:00
Belac Darkstorm 0403825c3d Doing some stuff 2017-04-06 09:20:00 -05:00
Belac Darkstorm 0f1bb3fabd Updated README 2017-04-06 09:00:09 -05:00
Belac Darkstorm 78c6842fab Tried some stuff that I didn't like
Revert "Jasdfasdf"

This reverts commit dc1edbad3a.
2017-04-06 08:47:11 -05:00
Belac Darkstorm dc1edbad3a Jasdfasdf 2017-04-06 08:46:39 -05:00
Belac Darkstorm 6dd00c5f8f Merge pull request #7 from CalebQ42/gtkUI
Settings, wine download and more!
2017-04-05 15:49:54 -05:00
Belac Darkstorm e68337886f Settings, wine download and more! 2017-04-05 15:49:21 -05:00
Belac Darkstorm 3b639f53fd Merge pull request #6 from CalebQ42/gtkUI
Gtk ui
2017-04-04 18:36:18 -05:00
Belac Darkstorm 3199ad88fd Finishing up gui 2017-04-04 18:35:28 -05:00
Belac Darkstorm a221d18d33 Starting UI remake work 2017-04-04 07:54:04 -05:00
Belac Darkstorm a9eeb3bb1c Last push before GUI redo 2017-04-04 01:32:13 -05:00
Belac Darkstorm 844a282fd7 Wine download finished for later on.
Going to start switching to another GUI library
2017-04-04 01:23:17 -05:00
Belac Darkstorm 9da352a315 Updating is working!! 2017-04-03 10:43:22 -05:00
Belac Darkstorm 34b8f7c926 Forgot to implement updating 2017-04-03 09:23:41 -05:00
Belac Darkstorm 5d5cedec58 Ready to test then bug fix :)
Also, I'm ALIVE!!!!
2017-04-03 09:17:49 -05:00
Belac Darkstorm 8441a8b752 Working on an auto-update mechanism 2017-04-03 08:23:25 -05:00
Belac Darkstorm d64d88e0a5 Tries to make PortableApps folder before failing 2016-09-23 14:32:30 -05:00
17 changed files with 1659 additions and 358 deletions
+15 -14
View File
@@ -2,37 +2,38 @@
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.
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:
Both of the below places provide linux executables that don't need libs installed on the host system:
The below place provides linux executables that don't need libs installed on the host system:
[AppImage](https://bintray.com/probono/AppImages)
<s>[Orbital-Apps](https://www.orbital-apps.com/blog/2016/introducing-universal-orbs)</s> (Only works if the Orb-Launcher is installed on the system, for some reason. [Issue](https://github.com/CalebQ42/LinuxPA/issues/3))
# 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 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, 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=`
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)
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.
Right now AppImages are simply supported via the native linux executable support, and you can download AppImages. (Woo)
# USB mount
Unfortunately Linux, by default, doesn't support running executables off of flash drives, requiring you to mount your drive with special mount arguments, I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
Unfortunately Linux, by default, doesn't support running executables off of FAT formated flash drives, requiring you to mount your drive with special mount arguments or format in a linux friendly format (such as EXT4). I personally use the arguments `exec,noauto,nodev,nosuid,umask=0000`
# Screenshots
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
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. Add settings menu
1. Add updater for .AppImage files
1. Download .AppImage files (maybe)
1. Check if all apps are closed when it closes and ask if you want to force stop the apps.
1. Portable wine???
1. MAKE IT BETTER  
1. Manual update check  
1. Better AppImage integrations (Specifically updating, getting information from the appimage, and better appimage downloading)
1. Automagic appimage updating (It will of course ask you beforehand)
1. Get information (such as name and icon) directly from an appimage
1. Better appimage downloading (probably based around [AppImageHub](https://appimage.github.io/apps/))
1. Sandboxing support
1. Check if all apps are closed when it closes and ask if you want to force stop the apps
+226 -180
View File
@@ -1,12 +1,14 @@
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"strings"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/math"
"github.com/gotk3/gotk3/gdk"
"github.com/gotk3/gotk3/gtk"
)
type app struct {
@@ -15,94 +17,55 @@ type app struct {
appimg []string
lin []string
ex []string
icon gxui.Texture
icon *gdk.Pixbuf
dir string
ini *os.File
wine bool
}
type appExNode struct {
ap app
exInd int
func (a *app) getTreeIter(store *gtk.TreeStore) *gtk.TreeIter {
it := store.Append(nil)
store.SetValue(it, 0, a.icon)
if portableHide {
store.SetValue(it, 1, strings.TrimSuffix(a.name, "Portable"))
} else {
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 *appExNode) launch() {
func (a *app) launch() {
if len(a.ex) == 1 {
if wine {
var cmd *exec.Cmd
if !contains(a.ap.lin, a.ap.ex[a.exInd]) {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[a.exInd]+"\"")
} else {
if !contains(a.lin, a.ex[0]) {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
}
} else {
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[0]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[0]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[0]+".config", 0777)
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
var cmd *exec.Cmd
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[a.exInd]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
func (a *appExNode) Count() int {
return 0
}
func (a *appExNode) NodeAt(int) gxui.TreeNode {
return nil
}
func (a *appExNode) ItemIndex(gxui.AdapterItem) int {
return -1
}
func (a *appExNode) Item() gxui.AdapterItem {
if wine {
return a.ap.ex[a.exInd]
}
return a.ap.lin[a.exInd]
}
func (a *appExNode) Create(the gxui.Theme) gxui.Control {
box := the.CreateLinearLayout()
box.SetDirection(gxui.LeftToRight)
box.SetVerticalAlignment(gxui.AlignMiddle)
img := the.CreateImage()
img.SetTexture(a.ap.icon)
img.SetExplicitSize(math.Size{H: 32, W: 32})
lbl := the.CreateLabel()
lbl.SetText(a.ap.ex[a.exInd])
box.AddChild(img)
box.AddChild(lbl)
box.OnDoubleClick(func(gxui.MouseEvent) {
a.launch()
})
return box
}
type appNode struct {
ap app
}
func (a *appNode) launch() {
if len(a.ap.ex) == 1 {
if wine {
var cmd *exec.Cmd
if !contains(a.ap.lin, a.ap.ex[0]) {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
} else {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
}
}
cmd.Stdout = os.Stdout
@@ -110,10 +73,14 @@ func (a *appNode) launch() {
cmd.Start()
} else {
var cmd *exec.Cmd
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[0]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[0]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[0]+".config", 0777)
}
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.ex[0]+"\"")
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[0]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -122,39 +89,51 @@ func (a *appNode) launch() {
} else {
if wine {
var cmd *exec.Cmd
if len(a.ap.lin) == 0 {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; wine \""+a.ap.ex[0]+"\"")
if len(a.lin) == 0 {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[0]+"\"")
}
} else {
var ind int
for i, v := range a.ap.lin {
for i, v := range a.lin {
if strings.HasSuffix(v, ".sh") {
ind = i
break
}
}
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[ind]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[ind]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[ind]+".config", 0777)
}
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[ind]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
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.ap.lin) != 0 {
if len(a.lin) != 0 {
var ind int
for i, v := range a.ap.lin {
for i, v := range a.lin {
if strings.HasSuffix(v, ".sh") {
ind = i
break
}
}
var cmd *exec.Cmd
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[ind]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[ind]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[ind]+".config", 0777)
}
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", ". PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[ind]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.ap.dir+"\"; \"./"+a.ap.lin[ind]+"\"")
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.lin[ind]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
@@ -164,109 +143,176 @@ func (a *appNode) launch() {
}
}
func (a *appNode) Count() int {
func (a *app) launchSub(sub int) {
if wine {
if len(a.ap.ex) > 1 {
return len(a.ap.ex)
}
return 0
}
if len(a.ap.lin) > 1 {
return len(a.ap.lin)
}
return 0
}
func (a *appNode) NodeAt(i int) gxui.TreeNode {
return &appExNode{ap: a.ap, exInd: i}
}
func (a *appNode) ItemIndex(item gxui.AdapterItem) int {
if wine {
for i, v := range a.ap.ex {
if v == item {
return i
}
var cmd *exec.Cmd
if !contains(a.lin, a.ex[sub]) {
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[0]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; wine \""+a.ex[sub]+"\"")
}
} else {
for i, v := range a.ap.lin {
if v == item {
return i
if paDirs && strings.HasSuffix(strings.ToLower(a.ex[sub]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[sub]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[sub]+".config", 0777)
}
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[sub]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} else {
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 paDirs && strings.HasSuffix(strings.ToLower(a.ex[sub]), ".appimage") {
os.Mkdir(a.dir+"/"+a.ex[sub]+".home", 0777)
os.Mkdir(a.dir+"/"+a.ex[sub]+".config", 0777)
}
if comEnbld {
cmd = exec.Command("/bin/sh", "-c", "export APPNAME="+a.name+";export FILENAME="+a.ex[sub]+";. PortableApps/LinuxPACom/common.sh || exit 1;cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+a.dir+"\"; \"./"+a.ex[sub]+"\"")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
return -1
}
func (a *appNode) Item() gxui.AdapterItem {
return a.ap.name
}
func (a *appNode) Create(the gxui.Theme) gxui.Control {
box := the.CreateLinearLayout()
box.SetDirection(gxui.LeftToRight)
box.SetPadding(math.CreateSpacing(2))
box.SetVerticalAlignment(gxui.AlignMiddle)
img := the.CreateImage()
if a.ap.icon != nil {
img.SetTexture(a.ap.icon)
}
img.SetExplicitSize(math.Size{H: 32, W: 32})
lbl := the.CreateLabel()
lbl.SetText(a.ap.name)
box.AddChild(img)
box.AddChild(lbl)
box.OnDoubleClick(func(gxui.MouseEvent) {
a.launch()
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)
})
return box
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.FileChooserDialogNewWith1Button("Select Icon", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Open", gtk.RESPONSE_ACCEPT)
filter, _ := gtk.FileFilterNew()
filter.AddPixbufFormats()
filter.SetName("Supported Pictures")
fil.AddFilter(filter)
but, _ := fil.AddButton("Cancel", gtk.RESPONSE_CANCEL)
but.Connect("clicked", func() {
fil.Close()
})
resp := fil.Run()
if resp == int(gtk.RESPONSE_ACCEPT) {
filename := fil.GetFilename()
_, err := os.Open(filename)
if err != nil {
fmt.Println(err)
return
}
pix, _ := gdk.PixbufNewFromFileAtSize(filename, 32, 32)
tmp.icon = pix
img.SetFromPixbuf(pix)
fil.Close()
}
})
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)
nameShow := tmp.name
if tmp.wine {
nameShow = strings.TrimSuffix(nameShow, " (Wine)")
}
txtBuf.SetText(nameShow)
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()
}
type catAdap struct {
gxui.AdapterBase
cat string
}
func (a *catAdap) setCat(cat string) {
a.cat = cat
a.DataChanged(false)
}
func (a *catAdap) refresh() {
a.DataChanged(false)
}
func (a *catAdap) Count() int {
if wine {
return len(master[a.cat])
func (a *app) makeIni() {
os.Remove(a.dir + "/appinfo.ini")
fil, err := os.Create(a.dir + "/appinfo.ini")
if err != nil {
return
}
return len(linmaster[a.cat])
}
func (a *catAdap) NodeAt(i int) gxui.TreeNode {
if wine {
return &appNode{ap: master[a.cat][i]}
}
return &appNode{ap: linmaster[a.cat][i]}
}
func (a *catAdap) Size(gxui.Theme) math.Size {
return math.Size{H: 34, W: math.MaxSize.W}
}
func (a *catAdap) ItemIndex(item gxui.AdapterItem) int {
if wine {
for i, v := range master[a.cat] {
if v.name == item {
return i
}
}
} else {
for i, v := range linmaster[a.cat] {
if v.name == item {
return i
}
}
}
return -1
ini := "[General]\n"
ini += "Category=" + a.cat + "\n"
ini += "Name=" + a.name + "\n"
wrt := bufio.NewWriter(fil)
wrt.WriteString(ini)
wrt.Flush()
}
+78
View File
@@ -0,0 +1,78 @@
package appimg
// Thanks to probono for the majority of this C code: https://discourse.appimage.org/t/accessing-appimage-desktop-file/173/4?u=calebq42
/*
#cgo CFLAGS: -I/usr/lib
#cgo LDFLAGS: -L/usr/lib/libappimage.so -lappimage
#cgo pkg-config: glib-2.0
#include <appimage/appimage.h>
#include <stdlib.h>
#include <glib.h>
#include <strings.h>
bool extract_desktop(char* appimageLoc,char* extractLoc){
char** files = appimage_list_files(appimageLoc);
g_autofree gchar *desktop_file = NULL;
gchar *extracted_desktop_file = extractLoc;
int i = 0;
for (; files[i] != NULL ; i++) {
// g_debug("AppImage file: %s", files[i]);
if (g_str_has_suffix (files[i],".desktop")) {
desktop_file = files[i];
g_debug("AppImage desktop file: %s", desktop_file);
break;
}
}
if(desktop_file == NULL) {
g_debug("AppImage desktop file not found");
appimage_string_list_free(files);
return FALSE;
}
appimage_extract_file_following_symlinks(appimageLoc, desktop_file,extracted_desktop_file);
appimage_string_list_free(files);
return TRUE;
}
bool extract_file(char* appimageLoc,char* filename,char* extractLoc){
char** files = appimage_list_files(appimageLoc);
g_autofree gchar *found_file = NULL;
gchar *extracted_file = extractLoc;
int i = 0;
for (; files[i] != NULL ; i++) {
g_debug("AppImage file: %s", files[i]);
if (strcmp(files[i],filename)==0) {
found_file = files[i];
g_debug("FileFound: %s", found_file);
}
}
if(found_file == NULL) {
g_debug("filenotfound");
appimage_string_list_free(files);
return FALSE;
}
appimage_extract_file_following_symlinks(appimageLoc, found_file,extracted_file);
appimage_string_list_free(files);
return TRUE;
}
*/
import "C"
import (
"errors"
"os"
"unsafe"
)
func GetDesktopFile(loc string) (*os.File, error) {
os.Remove("/tmp/my.desktop")
var locTmp *C.char = C.CString(loc)
defer C.free(unsafe.Pointer(locTmp))
var extractLoc *C.char = C.CString("/tmp/my.desktop")
defer C.free(unsafe.Pointer(extractLoc))
var out C.bool = C.extract_desktop(locTmp, extractLoc)
if out == false {
return nil, errors.New("Desktop File Not Found!")
}
return os.Open("/tmp/my.desktop")
}
+60
View File
@@ -0,0 +1,60 @@
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
@@ -0,0 +1,115 @@
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
}
}
}
+13
View File
@@ -0,0 +1,13 @@
package appimg
type appimg struct {
full string
name string
version string
}
func newApp(name string) appimg {
var out appimg
out.full = name
return out
}
+67
View File
@@ -0,0 +1,67 @@
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.full + "...")
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.full)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
name := strings.Split(ap.full, "-")[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+"Portable", 0777)
foldName = "PortableApps/" + name + "Portable"
}
os.Remove(foldName + "/" + ap.full)
fil, err := os.Create(foldName + "/" + ap.full)
if err != nil {
fmt.Println(err)
return
}
io.Copy(fil, resp.Body)
fil.Chmod(0777)
}(win, ap)
}
+144
View File
@@ -0,0 +1,144 @@
//Package appimg is for downloading new AppImages for LinuxPA
package appimg
import (
"fmt"
"io/ioutil"
"net/http"
"sort"
"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(newestVersionOnly bool, 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) {
if newestVersionOnly {
imgs := make([]appimg, 0)
a := make(map[string][]appimg)
names := make([]string, 0)
for i := range apch {
imgs = append(imgs, i)
}
for i, v := range imgs {
sp := strings.Split(v.full, "-")
if len(sp) >= 2 {
vers := sp[1]
removeLetters(vers)
imgs[i].version = vers
imgs[i].name = sp[0]
if _, ok := a[imgs[i].name]; !ok {
names = append(names, imgs[i].name)
}
a[imgs[i].name] = append(a[imgs[i].name], imgs[i])
}
}
sort.Strings(names)
for _, name := range names {
glib.IdleAdd(func(name string, list *gtk.ListBox, i appimg) {
lbl, _ := gtk.LabelNew(name)
list.Add(lbl)
apps = append(apps, i)
lbl.Show()
}, name, list, a[name][compareVersions(a[name])])
}
} else {
for i := range apch {
glib.IdleAdd(func(list *gtk.ListBox, i appimg) {
lbl, _ := gtk.LabelNew(i.full)
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)
}
+12
View File
@@ -0,0 +1,12 @@
package appimg
import "strings"
func removeLetters(vers string) string {
vers = strings.ToLower(vers)
letters := []string{"abcdefghijklmnopqrstuvwxyz"}
for _, v := range letters {
vers = strings.Replace(vers, v, "", -1)
}
return vers
}
+33
View File
@@ -0,0 +1,33 @@
package appimg
import (
"strconv"
"strings"
)
func compareVersions(imgs []appimg) int {
for i := range imgs {
imgs[i].version = removeLetters(imgs[i].version)
}
highest := 0
higharr := strings.Split(imgs[0].version, ".")
for i := 0; i < len(imgs); i++ {
if i != highest {
varr := strings.Split(imgs[i].version, ".")
if len(higharr) < len(varr) {
for j := 0; j < len(higharr); j++ {
h, _ := strconv.Atoi(higharr[j])
c, _ := strconv.Atoi(varr[j])
if h > c {
break
} else if c > h {
highest = i
higharr = varr
break
}
}
}
}
}
return highest
}
+92 -14
View File
@@ -1,39 +1,117 @@
package main
import (
"encoding/gob"
"flag"
"fmt"
"os"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/drivers/gl"
"github.com/nelsam/gxui/themes/dark"
"github.com/gotk3/gotk3/gtk"
)
const (
version = "2.1.4.0"
)
var (
dr gxui.Driver
th gxui.Theme
master map[string][]app
linmaster map[string][]app
cats []string
lin []string
wine bool
comEnbld bool
wineAvail bool
portableHide bool
betaUpdate bool
versionNewest = true
paDirs = true
)
func main() {
_, err := os.Open("PortableApps/LinuxPACom/common.sh")
if err == nil {
comEnbld = true
}
forced := flag.Bool("force-update", false, "Force the update dialog to be shown")
flag.Parse()
os.MkdirAll("PortableApps/LinuxPACom", 0777)
master = make(map[string][]app)
linmaster = make(map[string][]app)
gl.StartDriver(appMain)
uiStart(*forced)
}
func appMain(dri gxui.Driver) {
dr = dri
th = dark.CreateTheme(dr)
func uiStart(forced bool) {
gtk.Init(nil)
setup()
ui()
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, forced)
gtk.Main()
}
func savePrefs() {
os.Remove("PortableApps/LinuxPACom/Prefs.gob")
fil, err := os.Create("PortableApps/LinuxPACom/Prefs.gob")
if err != nil {
return
}
enc := gob.NewEncoder(fil)
err = enc.Encode(wine)
if err != nil {
return
}
err = enc.Encode(portableHide)
if err != nil {
return
}
err = enc.Encode(versionNewest)
if err != nil {
return
}
err = enc.Encode(paDirs)
if err != nil {
return
}
err = enc.Encode(betaUpdate)
if err != nil {
return
}
}
func loadPrefs() {
fil, err := os.Open("PortableApps/LinuxPACom/Prefs.gob")
if err != nil {
return
}
dec := gob.NewDecoder(fil)
err = dec.Decode(&wine)
if err != nil {
return
}
err = dec.Decode(&portableHide)
if err != nil {
return
}
err = dec.Decode(&versionNewest)
if err != nil {
return
}
err = dec.Decode(&paDirs)
if err != nil {
return
}
err = dec.Decode(&betaUpdate)
if err != nil {
return
}
}
func contains(arr []string, str string) bool {
+206
View File
@@ -0,0 +1,206 @@
package main
import (
"io/ioutil"
"os"
"os/exec"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
const (
commonHelp = "The common.sh is run before every app is launched and allows you to set variables such as $HOME. For directories, ALWAYS start the directory with $PWD which points to the directory where LinuxPA is. To allow for greater customization and isolation, you can use the $FILENAME variable which is the filename of the executable you're using and the $APPNAME variable which is the name of the app being lanched."
)
func settingsUI(parent *gtk.Window, onExit func()) {
win, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
win.SetTransientFor(parent)
parent.SetSensitive(false)
win.SetDefaultSize(600, 300)
win.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
win.Connect("destroy", func() {
savePrefs()
parent.SetSensitive(true)
onExit()
})
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")
wineCheck, _ := gtk.CheckButtonNewWithLabel("Show Windows apps (Wine)")
wineLbl, _ := gtk.LabelNew("PortableApps/LinuxPACom/Wine present")
dlWine.Connect("clicked", func() {
cb := make(chan bool)
downloadWine(win, cb)
go func() {
v := <-cb
if v {
setupTxt(comBuf)
wineLbl.Show()
}
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
}
glib.IdleAdd(func() {
if !wineAvail {
wineCheck.SetSensitive(false)
wineCheck.SetTooltipText("Download wine to run windows apps")
} else {
wineCheck.SetSensitive(true)
wineCheck.SetTooltipText("")
}
})
}()
})
if !comEnbld {
dlWine.SetSensitive(false)
dlWine.SetTooltipText("common.sh needed")
}
pthdCheck, _ := gtk.CheckButtonNewWithLabel("Hide \"Portable\" from app name")
pthdCheck.Connect("toggled", func() {
portableHide = pthdCheck.GetActive()
master = make(map[string][]app)
linmaster = make(map[string][]app)
cats = make([]string, 0)
lin = make([]string, 0)
setup()
})
pthdCheck.SetActive(portableHide)
if !wineAvail {
wineCheck.SetSensitive(false)
wineCheck.SetTooltipText("Download wine to run windows apps")
}
wineCheck.SetActive(wine)
wineCheck.Connect("toggled", func() {
wine = wineCheck.GetActive()
})
versCheck, _ := gtk.CheckButtonNewWithLabel("Only show newest app version in downloads (A bit iffy ATM)")
versCheck.SetActive(versionNewest)
versCheck.Connect("toggled", func() {
versionNewest = versCheck.GetActive()
})
paDirsCheck, _ := gtk.CheckButtonNewWithLabel("Create .home and .config directories for AppImages")
paDirsCheck.SetActive(paDirs)
paDirsCheck.Connect("toggled", func() {
paDirs = paDirsCheck.GetActive()
})
betaCheck, _ := gtk.CheckButtonNewWithLabel("Update to beta releases")
gnrl.Add(wineLbl)
gnrl.Add(dlWine)
gnrl.Add(pthdCheck)
gnrl.Add(wineCheck)
gnrl.Add(versCheck)
gnrl.Add(paDirsCheck)
gnrl.Add(betaCheck)
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)
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)
})
info, _ := gtk.ButtonNewWithLabel("Info")
info.Connect("clicked", func() {
infoBox, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
infoBox.SetTransientFor(parent)
infoBox.SetDefaultSize(300, 80)
infoBox.SetName("common.sh info")
infoBox.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
infolbl, _ := gtk.LabelNew(commonHelp)
infolbl.SetLineWrap(true)
infolbl.SetSizeRequest(200, 50)
box.Add(infolbl)
infoBox.Add(box)
infoBox.ShowAll()
infoBox.Show()
})
svBox.Add(sv)
svBox.Add(cnl)
svBox.Add(info)
com.Add(comScrl)
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("")
}
})
in, _ := gtk.ButtonNewWithLabel("Info")
in.Connect("clicked", func() {
infoBox, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
infoBox.SetTransientFor(parent)
infoBox.SetDefaultSize(300, 80)
infoBox.SetName("common.sh info")
infoBox.SetPosition(gtk.WIN_POS_CENTER_ON_PARENT)
box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
infolbl, _ := gtk.LabelNew(commonHelp)
infolbl.SetLineWrap(true)
infolbl.SetSizeRequest(200, 50)
box.Add(infolbl)
infoBox.Add(box)
infoBox.ShowAll()
infoBox.Show()
})
mkCom.Show()
com.Add(mkCom)
com.Add(in)
} 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
}
+51 -23
View File
@@ -2,21 +2,43 @@ package main
import (
"bufio"
"image"
"image/draw"
_ "image/png"
"os"
"os/exec"
"reflect"
"sort"
"strings"
"github.com/nelsam/gxui"
"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() {
panic("PortableApps folder not found!!")
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)
@@ -60,6 +82,9 @@ func processApp(fold string) (out app) {
if out.cat == "" {
out.cat = "Other"
}
if portableHide {
out.name = strings.TrimSuffix(out.name, "Portable")
}
out.icon = getIcon(fold)
folder, _ := os.Open(fold)
fis, _ := folder.Readdirnames(-1)
@@ -78,7 +103,7 @@ func processApp(fold string) (out app) {
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.HasPrefix(strings.ToLower(string(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)
}
@@ -89,6 +114,7 @@ func processApp(fold string) (out app) {
}
if len(out.lin) == 0 {
out.name += " (Wine)"
out.wine = true
}
return
}
@@ -100,6 +126,8 @@ func getCat(ini *os.File) string {
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)
@@ -113,15 +141,20 @@ func getName(ini *os.File) string {
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) gxui.Texture {
var pic *os.File
if folder, err := os.Open(fold + "/App/AppInfo"); err == nil {
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 {
@@ -137,24 +170,22 @@ func getIcon(fold string) gxui.Texture {
} else {
ind = sort.SearchStrings(pics, "appicon_32.png")
}
pic, _ = os.Open(fold + "/App/AppInfo/" + pics[ind])
pic = fold + "/App/AppInfo/" + pics[ind]
}
} else if fi, err := os.Open(fold + "/appicon.png"); err == nil {
pic = fi
} else {
return nil
img, _ := gtk.ImageNewFromIconName("application-x-executable", gtk.ICON_SIZE_BUTTON)
buf := img.GetPixbuf()
return buf
}
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
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)
@@ -165,8 +196,5 @@ func findInfo(fold string) *os.File {
}
}
}
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}
}
+175 -53
View File
@@ -1,66 +1,188 @@
package main
import (
"os"
"os/exec"
"github.com/nelsam/gxui"
"github.com/CalebQ42/LinuxPA/appimg"
"github.com/gotk3/gotk3/glib"
"github.com/gotk3/gotk3/gtk"
)
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))
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.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)
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()
})
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")
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()
})
}
}
})
_, 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()
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))
}
}
}
})
butBox.AddChild(pa)
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()
}
butBox.AddChild(wineBut)
} 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])
}
top.AddChild(butBox)
top.AddChild(splBox)
win.AddChild(top)
win.OnClose(dr.Terminate)
}
}
})
dnl.Connect("clicked", func() {
appimg.ShowUI(versionNewest, 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()
})
})
settings.Connect("clicked", func() {
settingsUI(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()
})
})
}
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
}
+262
View File
@@ -0,0 +1,262 @@
package main
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"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"
changelogURL = "https://www.dropbox.com/s/nmbk318er5kej5h/Changelog?dl=1"
changelogBetaURL = "https://www.dropbox.com/s/m8mo2o3nsvfqbfx/ChangelogBeta?dl=1"
)
//Thanks to https://www.socketloop.com/tutorials/golang-download-file-example
//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() (stable string, beta string) {
fil, err := os.Open("PortableApps/LinuxPACom/Version")
if err != nil {
return "Error!", ""
}
rdr := bufio.NewReader(fil)
out, _, _ := rdr.ReadLine()
stable = string(out)
out, _, _ = rdr.ReadLine()
beta = string(out)
return
}
func changelogDL() (bool, error) {
changelogFile, err := os.Create("PortableApps/LinuxPACom/Changelog")
if err != nil {
return false, err
}
changelogFile.Chmod(0777)
check := http.Client{
CheckRedirect: func(r *http.Request, via []*http.Request) error {
r.URL.Opaque = r.URL.Path
return nil
},
}
var response *http.Response
if betaUpdate {
response, err = check.Get(changelogBetaURL)
} else {
response, err = check.Get(changelogURL)
}
if err != nil {
return false, err
}
_, err = io.Copy(changelogFile, response.Body)
if err != nil {
return false, err
}
return true, nil
}
func getChangelog() string {
fil, err := os.Open("PortableApps/LinuxPACom/Changelog")
if err != nil {
return "Error!"
}
out, _ := ioutil.ReadAll(fil)
return string(out)
}
func checkForUpdate(stable, beta string) (bool, error) {
new := stable
if betaUpdate {
new = beta
}
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, forced bool) {
stat, err := versionDL()
if stat {
stable, beta := getVersionFileInfo()
if stable != "Error!" {
stat, err = checkForUpdate(stable, beta)
if stat || forced {
stat, err = changelogDL()
if stat {
updateWin, _ := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
updateWin.SetTransientFor(win)
updateWin.SetPosition(gtk.WIN_POS_CENTER)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
lbl, _ := gtk.LabelNew("There's a new update! Here's the changelog:")
tagTbl, _ := gtk.TextTagTableNew()
buf, _ := gtk.TextBufferNew(tagTbl)
tv, _ := gtk.TextViewNewWithBuffer(buf)
tv.SetEditable(false)
buf.SetText(getChangelog())
butBox, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5)
upBut, _ := gtk.ButtonNewWithLabel("Update")
upBut.Connect("clicked", func() {
updateWin.Close()
actuallyUpdate(win, forced)
})
cnlBut, _ := gtk.ButtonNewWithLabel("Cancel")
cnlBut.Connect("clicked", func() {
updateWin.Close()
})
butBox.Add(upBut)
butBox.Add(cnlBut)
topLvl.Add(lbl)
topLvl.Add(tv)
topLvl.Add(butBox)
topLvl.SetMarginBottom(10)
topLvl.SetMarginEnd(10)
topLvl.SetMarginStart(10)
topLvl.SetMarginTop(10)
updateWin.Add(topLvl)
updateWin.ShowAll()
updateWin.Show()
} else {
fmt.Println(err)
}
} else {
fmt.Println(err)
}
} else {
fmt.Println("Failed Version File Info")
}
} else {
fmt.Println(err)
}
}
func actuallyUpdate(win *gtk.Window, forced bool) {
updateWin, _ := gtk.WindowNew(gtk.WINDOW_POPUP)
updateWin.SetTransientFor(win)
updateWin.SetSizeRequest(150, 50)
topLvl, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 5)
spin, _ := gtk.SpinnerNew()
spin.Start()
lbl, _ := gtk.LabelNew("Updating")
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 {
stable, beta := getVersionFileInfo()
if stable != "Error!" {
stat, err = checkForUpdate(stable, beta)
if stat || forced {
if betaUpdate {
downloadUpdate(beta)
} else {
downloadUpdate(stable)
}
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
@@ -0,0 +1,101 @@
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)
}