62 Commits

Author SHA1 Message Date
Caleb Gardner 50105c242a EVEN MORE TESTING 2025-01-11 14:29:50 -06:00
Caleb Gardner 6e8d97f29b MORE MESSING AROUND 2025-01-11 13:16:58 -06:00
Caleb Gardner c8e0f08aae Started messing around with Raylib
Mainly just messing around
2025-01-11 06:35:32 -06:00
Caleb Gardner 916f9cc79b Update deps 2024-09-27 06:57:28 -05:00
Caleb Gardner e4e5adaf13 go mod tidy 2022-09-09 06:17:26 -05:00
Caleb Gardner 7a2ebd533e Update deps 2022-09-09 05:46:35 -05:00
Caleb Gardner 2f0ca5418c Updated readme and go version 2021-09-18 06:22:06 -05:00
Caleb Gardner ce9d4aed23 Fixed update download dialog 2020-11-28 03:52:10 -06:00
Caleb Gardner 712a5ab33d Removed stuff I don't need, now that I don't have a download UI 2020-11-28 03:33:50 -06:00
Caleb Gardner 6723f933b4 Forgot to up version number 2020-11-28 03:26:27 -06:00
Caleb Gardner 016fc35745 Download button now brings you to app image hub web page 2020-11-28 03:20:21 -06:00
Caleb Gardner ba5e3510ec some stuff for the future 2020-11-09 15:59:50 -06:00
Caleb Gardner 7e2d7ee14b Updated README 2020-11-09 15:30:14 -06:00
Caleb Gardner b20de4f1d6 Updated go.mod 2020-11-07 01:01:58 -06:00
Caleb Gardner d2e91baa6b Possibly full AppImage support 2020-11-06 04:54:22 -06:00
Caleb Gardner a0f22e480b Now using a new version of GoAppImage which should actually work.
Minor updates due to new library versions
Added go.mod to use Go's versioning system.
2020-11-06 03:44:34 -06:00
Belac Darkstorm 57f921c2cb Merge pull request #12 from probonopd/patch-1
https://appimage.github.io/
2019-01-18 18:37:35 -06:00
probonopd 55f897db46 https://appimage.github.io/ 2019-01-18 16:47:12 +00:00
Belac Darkstorm 3d9583281e AppImage's are now processed better
AppImage's desktop files are now extracted so name, category, and icon can be obtained
Made all icons be scaled so you don't get icons that are too big or small
2018-06-16 03:08:31 -05:00
Caleb ec4d66f6b2 Some refinement
Moved more complex appimage stuff to seperate package (github.com/CalebQ42/GoAppImage)
Moved settings to a seperate file for organization
Some work to allow asyncronouse app loading (Since goappimage is super slow)
Comments to show what's going to be there in the future.
2018-06-14 02:30:59 -05:00
Caleb c442ef5688 Removed debug code 2018-06-07 21:02:37 -05:00
Caleb 78d3723bf4 Finished work on AppImage desktop file extraction 2018-06-07 13:58:47 -05:00
Caleb 828b9f4cda Fixed a couple bugs relating to settings and wine apps 2018-06-04 18:11:49 -05:00
Caleb be64aa083f Added beta update support.
Started work on further appimage support
2018-06-04 17:34:15 -05:00
Belac 3111705cae Removed legacy gxui 2018-06-03 02:48:40 -05:00
Belac Darkstorm 868ae8f700 Update README.md 2018-01-01 16:21:45 -06:00
Caleb Gardner 226e9d6210 Changed $PANAME to $FILENAME
Added $APPNAME
Fixed a couple bugs
2017-08-10 19:05:54 -05:00
Belac Darkstorm 56748f043e Added stuff for appimages.
Shows changelog before updating.
2017-08-09 03:36:35 -05:00
Belac Darkstorm 3d3239fe0a Updated README 2017-08-08 12:39:41 -05:00
Belac Darkstorm 6e643b68ac Update README.md 2017-08-08 07:02:09 -05:00
Belac Darkstorm 539f33d25e Updated README 2017-04-18 09:21:30 -05:00
Belac Darkstorm 4d3cb9f486 updated 2017-04-14 04:07:55 -05:00
Belac Darkstorm a55c82483a Better download list parsing 2017-04-14 03:36:50 -05:00
Belac Darkstorm 9e9bb82025 Moved "Show windows apps" to settings
Added "Hide Portable from app names"
2017-04-14 01:56:36 -05:00
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
Belac Darkstorm 5eeb9cc702 Fixed some bugs (oops) 2016-09-22 20:25:26 -05:00
Belac Darkstorm fc3411e568 Added Button to launch PortableApps.com launcher. Added back common.sh support (oops) 2016-09-22 08:39:56 -05:00
Belac Darkstorm 77ce9e8ad4 appinfo.ini detection no longer capitalization dependent 2016-09-22 00:25:58 -05:00
Belac Darkstorm 63dd8ebb83 Added a bit better appinfo.ini detection 2016-09-22 00:21:00 -05:00
Belac Darkstorm 7cf45c9ac8 Allow for multiple executables. Double click to launch instead of the launch button 2016-09-22 00:11:32 -05:00
12 changed files with 409 additions and 485 deletions
+1
View File
@@ -0,0 +1 @@
testing/
+40 -21
View File
@@ -1,32 +1,51 @@
# LinuxPA
LinuxPA is a try to bring a [PortableApps.com](http://portableapps.com) type launcher to Linux.
# App Detection
LinuxPA looks in all folders in the PortableApps folder for, first, a script file (starts with the shebang (`#!`)) and, secondly, a native linux executable (starts with ELF). It will only add the first one it finds.
## How to use
Just double click on an app to launch it! If there are multiple executables, you can either select the specific executable, or if you just double click the app it'll launch the first linux executable 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.
## Simple App Setup
# 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`
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.
# Screenshots
Photos are found [Here](https://goo.gl/photos/VtBUL6DyZTMidj5n6)
## AppImage Support
# 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???
[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
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). 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
+11
View File
@@ -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
)
+8
View File
@@ -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=
+260
View File
@@ -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)
}
+48
View File
@@ -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()
}
}
+39
View File
@@ -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
}
+2 -179
View File
@@ -1,184 +1,7 @@
package main
import (
"bufio"
"os"
"path"
"reflect"
"sort"
"strings"
"github.com/nelsam/gxui/drivers/gl"
)
var (
appMaster map[string][]prtap
cats []string
wineOnly []string
linOnly []string
conf *os.File
common string
commEnbl bool
)
type prtap struct {
name string
cat string
ex string
desc string
wine bool
}
import "github.com/CalebQ42/LinuxPA/internal/ui"
func main() {
commEnbl = true
appMaster = make(map[string][]prtap)
os.Mkdir("PortableApps", 0777)
os.Mkdir("PortableApps/LinuxPACom", 0777)
common = "PortableApps/LinuxPACom/common.sh"
_, err := os.Open(common)
if os.IsNotExist(err) {
commEnbl = false
}
pa, err := os.Open("PortableApps")
if err != nil {
panic(err)
}
appstmp, _ := pa.Readdir(-1)
var folds []string
for _, v := range appstmp {
if v.IsDir() && v.Name() != "LinuxPACom" && v.Name() != "PortableApps.com" {
folds = append(folds, v.Name())
}
}
sort.Strings(folds)
for _, v := range folds {
fi, _ := os.Open("PortableApps/" + v)
pat := processApp(fi)
if (pat != prtap{}) {
if _, ok := appMaster[pat.cat]; !ok {
if pat.wine {
wineOnly = append(wineOnly, pat.cat)
cats = append(cats, pat.cat)
} else {
linOnly = append(linOnly, pat.cat)
cats = append(cats, pat.cat)
}
} else {
if !pat.wine {
for i, v := range wineOnly {
if pat.cat == v {
wineOnly = append(wineOnly[:i], wineOnly[i+1:]...)
linOnly = append(linOnly, pat.cat)
break
}
}
}
}
appMaster[pat.cat] = append(appMaster[pat.cat], pat)
}
}
sort.Strings(linOnly)
sort.Strings(wineOnly)
sort.Strings(cats)
gl.StartDriver(uiMain)
}
func processApp(fi *os.File) (out prtap) {
fis, _ := fi.Readdir(-1)
if fil, err := os.Open(fi.Name() + "/App/AppInfo/appinfo.ini"); err == nil {
out.name = getName(fil)
fil, _ = os.Open(fi.Name() + "/App/AppInfo/appinfo.ini")
out.cat = getCat(fil)
} else if fil, err := os.Open(fi.Name() + "/appinfo.ini"); err == nil {
out.name = getName(fil)
fil, _ = os.Open(fi.Name() + "/appinfo.ini")
out.cat = getCat(fil)
} else {
out.cat = "Other"
}
if out.name == "" {
out.name = path.Base(fi.Name())
}
if out.cat == "" {
out.cat = "Other"
}
//executable detection
wd, _ := os.Getwd()
var rdr *bufio.Reader
for _, v := range fis {
fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
if err == nil {
stat, _ := fil.Stat()
if !stat.IsDir() {
rdr = bufio.NewReader(fil)
shebang := []byte{'#', '!'}
two := make([]byte, 2)
rdr.Read(two)
if reflect.DeepEqual(shebang, two) {
out.ex = wd + "/" + fi.Name() + "/" + v.Name()
rdr.Reset(fil)
return
}
}
}
}
for _, v := range fis {
fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
if err == nil {
stat, _ := fil.Stat()
if !stat.IsDir() {
rdr = bufio.NewReader(fil)
thr := make([]byte, 4)
rdr.Read(thr)
if strings.Contains(string(thr), "ELF") {
out.ex = wd + "/" + fi.Name() + "/" + v.Name()
rdr.Reset(fil)
return
}
}
}
}
for _, v := range fis {
fil, err := os.Open(wd + "/" + fi.Name() + "/" + v.Name())
if err == nil {
stat, _ := fil.Stat()
if !stat.IsDir() && strings.HasSuffix(stat.Name(), "exe") {
out.wine = true
out.ex = wd + "/" + fi.Name() + "/" + v.Name()
out.name += " (Wine)"
return
}
}
}
return prtap{}
}
func getCat(fi *os.File) (out string) {
rdr := bufio.NewReader(fi)
var err error
var ln []byte
for err == nil {
ln, _, err = rdr.ReadLine()
str := string(ln)
if strings.HasPrefix(str, "Category=") {
out = strings.TrimPrefix(str, "Category=")
return
}
}
return
}
func getName(fi *os.File) (out string) {
rdr := bufio.NewReader(fi)
var err error
var ln []byte
for err == nil {
ln, _, err = rdr.ReadLine()
str := string(ln)
if strings.HasPrefix(str, "Name=") {
out = strings.TrimPrefix(str, "Name=")
return
}
}
return
ui.Test()
}
BIN
View File
Binary file not shown.
-130
View File
@@ -1,130 +0,0 @@
package main
import (
"image"
"image/draw"
_ "image/png"
"os"
"path"
"sort"
"strings"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/math"
)
type prtapAdap struct {
gxui.AdapterBase
wine bool
master []prtap
cur []prtap
}
func (p *prtapAdap) SetApps(apps []prtap) {
p.master = apps
if p.wine {
p.cur = p.master
} else {
p.cur = make([]prtap, 0)
for _, v := range p.master {
if !v.wine {
p.cur = append(p.cur, v)
}
}
}
p.DataChanged(false)
}
func (p *prtapAdap) Count() int {
return len(p.cur)
}
func (p *prtapAdap) Wine(show bool) {
p.wine = show
if show {
p.cur = p.master
} else {
p.cur = make([]prtap, 0)
for _, v := range p.master {
if !v.wine {
p.cur = append(p.cur, v)
}
}
}
p.DataChanged(false)
}
func (p *prtapAdap) Create(th gxui.Theme, index int) gxui.Control {
box := th.CreateLinearLayout()
box.SetPadding(math.CreateSpacing(2))
box.SetDirection(gxui.LeftToRight)
box.SetVerticalAlignment(gxui.AlignMiddle)
dir := path.Dir(p.cur[index].ex)
if fold, err := os.Open(dir + "/App/AppInfo"); err == nil {
var pics []string
fi, _ := fold.Readdirnames(-1)
for _, v := range fi {
if strings.HasPrefix(v, "appicon_") && strings.HasSuffix(v, ".png") {
pics = append(pics, v)
}
}
if len(pics) > 0 {
ind := sort.SearchStrings(pics, "appicon_128.png")
if ind == len(pics) {
ind = len(pics) - 1
}
imgfi, _ := os.Open(dir + "/App/AppInfo/" + pics[ind])
img, _, err := image.Decode(imgfi)
if err == nil {
rgba := image.NewRGBA(img.Bounds())
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
tex := dr.CreateTexture(rgba, 1)
icon := th.CreateImage()
icon.SetExplicitSize(math.Size{H: 32, W: 32})
icon.SetTexture(tex)
box.AddChild(icon)
}
}
} else if fi, err := os.Open(dir + "/appicon.png"); err == nil {
img, _, err := image.Decode(fi)
if err == nil {
rgba := image.NewRGBA(img.Bounds())
draw.Draw(rgba, img.Bounds(), img, image.ZP, draw.Src)
tex := dr.CreateTexture(rgba, 1)
icon := th.CreateImage()
icon.SetExplicitSize(math.Size{H: 32, W: 32})
icon.SetTexture(tex)
box.AddChild(icon)
}
} else {
//Creating empty Image so that names line up
icon := th.CreateImage()
icon.SetExplicitSize(math.Size{H: 32, W: 32})
box.AddChild(icon)
}
lbl := th.CreateLabel()
lbl.SetText(p.cur[index].name)
box.AddChild(lbl)
return box
}
func (p *prtapAdap) ItemAt(index int) gxui.AdapterItem {
return p.cur[index]
}
func (p *prtapAdap) ItemIndex(item gxui.AdapterItem) int {
it, ok := item.(prtap)
if !ok {
return -1
}
for i, v := range p.cur {
if v == it {
return i
}
}
return -1
}
func (p *prtapAdap) Size(gxui.Theme) math.Size {
return math.Size{W: math.MaxSize.W, H: 36}
}
-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}
}
-90
View File
@@ -1,90 +0,0 @@
package main
import (
"fmt"
"os"
"os/exec"
"path"
"github.com/nelsam/gxui"
"github.com/nelsam/gxui/themes/dark"
)
var (
dr gxui.Driver
)
func uiMain(dri gxui.Driver) {
dr = dri
catAdap := &StrList{}
catAdap.SetStrings(linOnly)
appAdap := &prtapAdap{}
appAdap.Wine(false)
th := dark.CreateTheme(dr)
win := th.CreateWindow(500, 500, "LinuxPA")
top := th.CreateLinearLayout()
top.SetDirection(gxui.BottomToTop)
top.SetHorizontalAlignment(gxui.AlignRight)
spl := th.CreateSplitterLayout()
spl.SetOrientation(gxui.Horizontal)
catlist := th.CreateList()
catlist.SetAdapter(catAdap)
catlist.OnItemClicked(func(_ gxui.MouseEvent, it gxui.AdapterItem) {
str := it.(string)
appAdap.SetApps(appMaster[str])
})
applist := th.CreateList()
applist.SetAdapter(appAdap)
spl.AddChild(catlist)
spl.AddChild(applist)
but := th.CreateLinearLayout()
but.SetDirection(gxui.RightToLeft)
launch := th.CreateButton()
launch.SetText("Launch!")
launch.OnClick(func(gxui.MouseEvent) {
if appAdap.ItemIndex(applist.Selected()) != -1 {
app := applist.Selected().(prtap)
dir, fi := path.Split(app.ex)
var cmd *exec.Cmd
if app.wine {
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; wine \""+fi+"\"")
} else {
if commEnbl {
cmd = exec.Command("/bin/sh", "-c", ". "+common+" || exit 1;cd \""+dir+"\"; \"./"+fi+"\"")
} else {
cmd = exec.Command("/bin/sh", "-c", "cd \""+dir+"\"; \"./"+fi+"\"")
}
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Start()
}
})
if _, err := exec.LookPath("wine"); err == nil {
fmt.Println("Wine found!")
wine := th.CreateButton()
wine.SetType(gxui.ToggleButton)
wine.OnClick(func(gxui.MouseEvent) {
if wine.IsChecked() {
catAdap.SetStrings(cats)
appAdap.Wine(true)
} else {
catAdap.SetStrings(linOnly)
appAdap.Wine(false)
}
})
wine.SetText("Show Windows Apps")
wine.SetChecked(appAdap.wine)
but.AddChild(wine)
} else {
fmt.Println("Wine not found!")
}
but.AddChild(launch)
top.AddChild(but)
top.AddChild(spl)
win.AddChild(top)
win.OnClose(func() {
dr.Terminate()
})
}