diff --git a/ChangeLog.md b/ChangeLog.md index a5e14b1..e8a5237 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,4 +1,7 @@ +# 0.7.6 +- Now it only redraws the screen when there are changes (like frame draw requests from wayland, mouse movement, etc), reducing CPU usage, and network bandwidth for remote sessions. +- Moved profiling code behind a build tag to reduce binary size for normal users. # 0.7.5 - Converted code to entriely go (with a tiny bit of c). THis simplifies the build process and reduces dependencies. This lets us easily port to new platforms like arm64. diff --git a/Makefile b/Makefile index 81a9a30..daba74b 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ .DELETE_ON_ERROR: -bin_name := dist/$(if $(PLATFORM),$(PLATFORM)/,)$(if $(STATIC_BUILD),static,)/term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file +bin_name := dist/$(if $(PLATFORM),$(PLATFORM)/,)$(if $(STATIC_BUILD),static,)/$(ARCH_PREFIX)term.everything❗mmulet.com-dont_forget_to_chmod_+x_this_file protocols_files := $(shell find ./wayland/generate) diff --git a/Readme.md b/Readme.md index 5e45c43..728eab4 100755 --- a/Readme.md +++ b/Readme.md @@ -4,7 +4,7 @@ @@ -13,8 +13,8 @@ - - + +
- icon2 + icon2

Term.Everything❗

Download the beta test now!
Works on both x11 and Wayland host systems.Now written in go!Typescript version here
@@ -91,7 +91,7 @@ And this isn't even full resolution! Checkout the [full vid in in the discussion Check out the [help file here](./resources/help.md) for a usage guide on how to use `term.everything❗` ## Contributing -term.everything❗ is written in developer friendly [Typescript](https://www.typescriptlang.org/) using the [bun](https://bun.com/) engine, with a just a smidge of C++. +term.everything❗ is written in developer friendly [Go](https://go.dev/), with a just a smidge of C. See [./Contributing.md](./Contributing.md). ## Legal: diff --git a/distribute.sh b/distribute.sh index 26cb0d2..30f84a1 100755 --- a/distribute.sh +++ b/distribute.sh @@ -57,7 +57,7 @@ fi if [ -z "${PLATFORM+x}" ]; then PLATFORM_ARG="" else - PLATFORM_ARG="--platform $PLATFORM -e PLATFORM=$PLATFORM -e MULTI_PLATFORM=1" + PLATFORM_ARG="--platform $PLATFORM -e PLATFORM=$PLATFORM -e MULTI_PLATFORM=1 -e ARCH_PREFIX=$ARCH_PREFIX" fi $PODMAN run \ diff --git a/main.go b/main.go index d75f313..f7256b1 100644 --- a/main.go +++ b/main.go @@ -1,22 +1,11 @@ package main import ( - "log" - "net/http" - _ "net/http/pprof" - "github.com/mmulet/term.everything/termeverything" ) //go:generate go generate ./wayland -func init() { - go func() { - log.Println("pprof at http://127.0.0.1:6060/debug/pprof/") - _ = http.ListenAndServe("127.0.0.1:6060", nil) - }() -} - func main() { termeverything.MainLoop() } diff --git a/resources/HowIDidIt.md b/resources/HowIDidIt.md index a1e76cc..72e3422 100644 --- a/resources/HowIDidIt.md +++ b/resources/HowIDidIt.md @@ -40,7 +40,7 @@ So, this means we can do anything we want, so let's output to the terminal! I take the output given to us by the client and convert the images to terminal output, the utf8 characters with ansi escape codes via the [chafa library](https://github.com/hpjansson/chafa/). For input, I take the keyboard and mouse (yes terminals support mice) -from the stdin. And that's it! Of course, there are about 10K lines of code needed to actually do this in practice, but if you're interested in that I invite you to [check out the source code](../src/). +from the stdin. And that's it! Of course, there are about 10K lines of code needed to actually do this in practice, but if you're interested in that I invite you to [check out the source code](../termeverything/). ## What else can you do with wayland I have many other crazy ideas of what else to do custom wayland display server, so stay tuned. diff --git a/resources/multiplatform.sh b/resources/multiplatform.sh index 717ed46..b711b32 100755 --- a/resources/multiplatform.sh +++ b/resources/multiplatform.sh @@ -1,5 +1,5 @@ #!/bin/bash -PLATFORM=linux/aarch64 ./distribute.sh -PLATFORM=linux/amd64 ./distribute.sh \ No newline at end of file +PLATFORM=linux/aarch64 ARCH_PREFIX=ARM- ./distribute.sh +PLATFORM=linux/amd64 ARCH_PREFIX= ./distribute.sh \ No newline at end of file diff --git a/termeverything/ParseArgs.go b/termeverything/ParseArgs.go index 091f0b5..808f79f 100644 --- a/termeverything/ParseArgs.go +++ b/termeverything/ParseArgs.go @@ -14,7 +14,7 @@ var helpFile string //go:embed resources/LICENSES.txt var licensesFile string -const version = "0.7.5" +const version = "0.7.6" type CommandLineArgs struct { WaylandDisplayNameArg string diff --git a/termeverything/TerminalDrawLoop.go b/termeverything/TerminalDrawLoop.go index ca204ca..feab3ad 100644 --- a/termeverything/TerminalDrawLoop.go +++ b/termeverything/TerminalDrawLoop.go @@ -1,6 +1,7 @@ package termeverything import ( + "os" "slices" "strconv" "time" @@ -10,6 +11,18 @@ import ( "github.com/mmulet/term.everything/wayland/protocols" ) +type FrameInputState struct { + KeysPressedThisFrame map[Linux_Event_Codes]bool + MouseMoveThisFrame bool +} + +func MakeFrameInputState() FrameInputState { + return FrameInputState{ + KeysPressedThisFrame: make(map[Linux_Event_Codes]bool), + MouseMoveThisFrame: false, + } +} + type TerminalDrawLoop struct { VirtualMonitorSize wayland.Size @@ -42,7 +55,10 @@ type TerminalDrawLoop struct { StatusLine *Status_Line - GetClients chan *wayland.Client + GetClients chan *wayland.Client + FirstDrawDone bool + LastDrawSize framebuffertoansi.WinSize + FrameInputState FrameInputState } func MakeTerminalDrawLoop(desktop_size wayland.Size, @@ -74,6 +90,7 @@ func MakeTerminalDrawLoop(desktop_size wayland.Size, StatusLine: MakeStatusLine(), FrameEvents: frameEvents, GetClients: make(chan *wayland.Client, 32), + FrameInputState: MakeFrameInputState(), } if args != nil && args.MaxFrameRate != "" { if fps, err := strconv.ParseFloat(args.MaxFrameRate, 64); err == nil && fps > 0 { @@ -98,17 +115,7 @@ func (tw *TerminalDrawLoop) GetAppTitle() *string { return nil } -func (tw *TerminalDrawLoop) DrawToTerminal(start_of_frame float64, status_line string) { - if tw.MinTerminalTimeSeconds != nil { - last := 0.0 - if tw.TimeOfLastTerminalDraw != nil { - last = *tw.TimeOfLastTerminalDraw - } - if start_of_frame-last < *tw.MinTerminalTimeSeconds { - return - } - tw.TimeOfLastTerminalDraw = &start_of_frame - } +func (tw *TerminalDrawLoop) DrawToTerminal(status_line string) { // if protocols.DebugRequests { // fmt.Println("Debugging!!!") @@ -116,28 +123,25 @@ func (tw *TerminalDrawLoop) DrawToTerminal(start_of_frame float64, status_line s // fmt.Println("Not debugging.") // } - if !protocols.DebugRequests { - var statusLine *string - if !tw.HideStatusBar { - statusLine = &status_line - } - - widthCells, heightCells := tw.DrawState.DrawDesktop( - tw.Desktop.Buffer, - tw.VirtualMonitorSize.Width, - tw.VirtualMonitorSize.Height, - statusLine, - ) - tw.SharedRenderedScreenSize.WidthCells = &widthCells - tw.SharedRenderedScreenSize.HeightCells = &heightCells + var statusLine *string + if !tw.HideStatusBar { + statusLine = &status_line } + widthCells, heightCells := tw.DrawState.DrawDesktop( + tw.Desktop.Buffer, + tw.VirtualMonitorSize.Width, + tw.VirtualMonitorSize.Height, + statusLine, + ) + tw.SharedRenderedScreenSize.WidthCells = &widthCells + tw.SharedRenderedScreenSize.HeightCells = &heightCells + } func (tw *TerminalDrawLoop) MainLoop() { - keys_pressed_this_frame := map[Linux_Event_Codes]bool{} for { - tw.DrawClients(keys_pressed_this_frame) + tw.DrawClients() timeout := time.After(time.Duration(tw.DesiredFrameTimeSeconds * float64(time.Second))) for { @@ -145,9 +149,10 @@ func (tw *TerminalDrawLoop) MainLoop() { case code := <-tw.FrameEvents: switch c := code.(type) { case *KeyCode: - keys_pressed_this_frame[c.KeyCode] = true + tw.FrameInputState.KeysPressedThisFrame[c.KeyCode] = true case *PointerMove: tw.StatusLine.UpdateMousePosition(c) + tw.FrameInputState.MouseMoveThisFrame = true case *PointerButtonPress: tw.StatusLine.HandleTerminalMousePress(true) case *PointerButtonRelease: @@ -170,8 +175,8 @@ func (tw *TerminalDrawLoop) MainLoop() { } } -func (tw *TerminalDrawLoop) DrawClients(keys_pressed_this_frame map[Linux_Event_Codes]bool) { - +func (tw *TerminalDrawLoop) DrawClients() { + defer tw.ResetFrameState() start_of_frame := float64(time.Now().UnixMilli()) / 1000.0 var delta_time float64 if tw.TimeOfStartOfLastFrame != nil { @@ -179,12 +184,13 @@ func (tw *TerminalDrawLoop) DrawClients(keys_pressed_this_frame map[Linux_Event_ } else { delta_time = tw.DesiredFrameTimeSeconds } - + num_draw_requests := 0 for _, s := range tw.Clients { for { select { case callback_id := <-s.FrameDrawRequests: protocols.WlCallback_done(s, callback_id, uint32(time.Now().UnixMilli())) + num_draw_requests++ default: goto DoneCallbacks } @@ -224,9 +230,11 @@ func (tw *TerminalDrawLoop) DrawClients(keys_pressed_this_frame map[Linux_Event_ tw.Desktop.DrawClients(tw.Clients) - status_line := tw.StatusLine.Draw(delta_time, tw.GetAppTitle(), keys_pressed_this_frame) + status_line := tw.StatusLine.Draw(delta_time, tw.GetAppTitle(), tw.FrameInputState.KeysPressedThisFrame) - tw.DrawToTerminal(start_of_frame, status_line) + if tw.ShouldDrawFrame(start_of_frame, num_draw_requests) { + tw.DrawToTerminal(status_line) + } // const draw_time = Date.now(); @@ -239,5 +247,43 @@ func (tw *TerminalDrawLoop) DrawClients(keys_pressed_this_frame map[Linux_Event_ tw.StatusLine.PostFrame(delta_time) - clear(keys_pressed_this_frame) +} + +func (tw *TerminalDrawLoop) ResetFrameState() { + tw.FrameInputState.MouseMoveThisFrame = false + clear(tw.FrameInputState.KeysPressedThisFrame) +} + +func (tw *TerminalDrawLoop) ShouldDrawFrame(start_of_frame float64, num_draw_requests int) (should_draw bool) { + defer func() { + if should_draw { + tw.FirstDrawDone = true + } + }() + if tw.MinTerminalTimeSeconds != nil { + last := 0.0 + if tw.TimeOfLastTerminalDraw != nil { + last = *tw.TimeOfLastTerminalDraw + } + if start_of_frame-last < *tw.MinTerminalTimeSeconds { + return false + } + tw.TimeOfLastTerminalDraw = &start_of_frame + } + if protocols.DebugRequests { + return false + } + + if winsize, err := framebuffertoansi.GetWinsize(os.Stdout.Fd()); err == nil { + defer func() { + tw.LastDrawSize = winsize + }() + if winsize != tw.LastDrawSize { + return true + } + } + if num_draw_requests == 0 { + return tw.FrameInputState.MouseMoveThisFrame || !tw.FirstDrawDone + } + return true } diff --git a/termeverything/profile.go b/termeverything/profile.go new file mode 100644 index 0000000..f13b43f --- /dev/null +++ b/termeverything/profile.go @@ -0,0 +1,18 @@ +//go:build profile +// +build profile + +package termeverything + +import ( + _ "net/http/pprof" + + "log" + "net/http" +) + +func init() { + go func() { + log.Println("pprof at http://127.0.0.1:6060/debug/pprof/") + _ = http.ListenAndServe("127.0.0.1:6060", nil) + }() +}