mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-27 18:51:41 +02:00
Start work on the transmit backend
This commit is contained in:
@@ -147,6 +147,22 @@ func on_detect_timeout(timer_id loop.IdType) error {
|
|||||||
|
|
||||||
func on_initialize() (string, error) {
|
func on_initialize() (string, error) {
|
||||||
var iid uint32
|
var iid uint32
|
||||||
|
sz, err := lp.ScreenSize()
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to query terminal for screen size with error: %w", err)
|
||||||
|
}
|
||||||
|
if sz.WidthPx == 0 || sz.HeightPx == 0 {
|
||||||
|
return "", fmt.Errorf("Terminal does not support reporting screen sizes in pixels, use a terminal such as kitty, WezTerm, Konsole, etc. that does.")
|
||||||
|
}
|
||||||
|
if opts.Clear {
|
||||||
|
cc := &graphics.GraphicsCommand{}
|
||||||
|
cc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_free_visible)
|
||||||
|
cc.WriteWithPayloadToLoop(lp, nil)
|
||||||
|
}
|
||||||
|
if opts.TransferMode != "detect" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
query_in_flight = true
|
query_in_flight = true
|
||||||
lp.AddTimer(time.Duration(opts.DetectionTimeout*float64(time.Second)), false, on_detect_timeout)
|
lp.AddTimer(time.Duration(opts.DetectionTimeout*float64(time.Second)), false, on_detect_timeout)
|
||||||
g := func(t graphics.GRT_t, payload string) uint32 {
|
g := func(t graphics.GRT_t, payload string) uint32 {
|
||||||
@@ -157,13 +173,6 @@ func on_initialize() (string, error) {
|
|||||||
g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
|
g1.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(payload))
|
||||||
return iid
|
return iid
|
||||||
}
|
}
|
||||||
sz, err := lp.ScreenSize()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("Failed to query terminal for screen size with error: %w", err)
|
|
||||||
}
|
|
||||||
if sz.WidthPx == 0 || sz.HeightPx == 0 {
|
|
||||||
return "", fmt.Errorf("Terminal does not support reporting screen sizes via the TIOCGWINSZ ioctl")
|
|
||||||
}
|
|
||||||
keep_going.Store(true)
|
keep_going.Store(true)
|
||||||
screen_size = sz
|
screen_size = sz
|
||||||
if !opts.DetectSupport && num_of_items > 0 {
|
if !opts.DetectSupport && num_of_items > 0 {
|
||||||
@@ -207,11 +216,6 @@ func on_query_finished() (err error) {
|
|||||||
if transfer_by_stream != supported {
|
if transfer_by_stream != supported {
|
||||||
return fmt.Errorf("This terminal emulator does not support the graphics protocol, use a terminal emulator such as kitty that does support it")
|
return fmt.Errorf("This terminal emulator does not support the graphics protocol, use a terminal emulator such as kitty that does support it")
|
||||||
}
|
}
|
||||||
if opts.Clear {
|
|
||||||
cc := &graphics.GraphicsCommand{}
|
|
||||||
cc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_free_visible)
|
|
||||||
cc.WriteWithPayloadToLoop(lp, nil)
|
|
||||||
}
|
|
||||||
if opts.DetectSupport {
|
if opts.DetectSupport {
|
||||||
switch {
|
switch {
|
||||||
case transfer_by_memory == supported:
|
case transfer_by_memory == supported:
|
||||||
@@ -224,10 +228,7 @@ func on_query_finished() (err error) {
|
|||||||
quit_loop()
|
quit_loop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if num_of_items <= 0 {
|
return on_wakeup()
|
||||||
quit_loop()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func on_query_response(g *graphics.GraphicsCommand) (err error) {
|
func on_query_response(g *graphics.GraphicsCommand) (err error) {
|
||||||
@@ -290,6 +291,9 @@ func quit_loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func on_wakeup() error {
|
func on_wakeup() error {
|
||||||
|
if query_in_flight {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
have_more := true
|
have_more := true
|
||||||
for have_more {
|
for have_more {
|
||||||
select {
|
select {
|
||||||
@@ -297,9 +301,9 @@ func on_wakeup() error {
|
|||||||
num_of_items--
|
num_of_items--
|
||||||
if imgd.err != nil {
|
if imgd.err != nil {
|
||||||
print_error("Failed to process \x1b[31m%s\x1b[39m: %v\r\n", imgd.source_name, imgd.err)
|
print_error("Failed to process \x1b[31m%s\x1b[39m: %v\r\n", imgd.source_name, imgd.err)
|
||||||
continue
|
} else {
|
||||||
|
transmit_image(imgd)
|
||||||
}
|
}
|
||||||
lp.QueueWriteString("Processed " + imgd.source_name + "\r\n")
|
|
||||||
default:
|
default:
|
||||||
have_more = false
|
have_more = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,14 +135,19 @@ func (self *opened_input) Release() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type image_frame struct {
|
||||||
|
filename string
|
||||||
|
in_memory_bytes []byte
|
||||||
|
filename_is_temporary bool
|
||||||
|
width, height int
|
||||||
|
}
|
||||||
|
|
||||||
type image_data struct {
|
type image_data struct {
|
||||||
canvas_width, canvas_height int
|
canvas_width, canvas_height int
|
||||||
format_uppercase string
|
format_uppercase string
|
||||||
available_width, available_height int
|
available_width, available_height int
|
||||||
needs_scaling, needs_conversion bool
|
needs_scaling, needs_conversion bool
|
||||||
filename string
|
frames []image_frame
|
||||||
in_memory_bytes []byte
|
|
||||||
filename_is_temporary bool
|
|
||||||
|
|
||||||
// for error reporting
|
// for error reporting
|
||||||
err error
|
err error
|
||||||
@@ -150,6 +155,7 @@ type image_data struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func set_basic_metadata(imgd *image_data) {
|
func set_basic_metadata(imgd *image_data) {
|
||||||
|
imgd.frames = make([]image_frame, 0, 32)
|
||||||
imgd.available_width = int(screen_size.WidthPx)
|
imgd.available_width = int(screen_size.WidthPx)
|
||||||
imgd.available_height = 10 * imgd.canvas_height
|
imgd.available_height = 10 * imgd.canvas_height
|
||||||
if place != nil {
|
if place != nil {
|
||||||
@@ -173,12 +179,15 @@ func report_error(source_name, msg string, err error) {
|
|||||||
|
|
||||||
func make_output_from_input(imgd *image_data, f *opened_input) {
|
func make_output_from_input(imgd *image_data, f *opened_input) {
|
||||||
bb, ok := f.file.(*BytesBuf)
|
bb, ok := f.file.(*BytesBuf)
|
||||||
|
frame := &imgd.frames[0]
|
||||||
|
frame.width = imgd.canvas_width
|
||||||
|
frame.height = imgd.canvas_height
|
||||||
if ok {
|
if ok {
|
||||||
imgd.in_memory_bytes = bb.data
|
frame.in_memory_bytes = bb.data
|
||||||
} else {
|
} else {
|
||||||
imgd.filename = f.file.(*os.File).Name()
|
frame.filename = f.file.(*os.File).Name()
|
||||||
if f.name_to_unlink != "" {
|
if f.name_to_unlink != "" {
|
||||||
imgd.filename_is_temporary = true
|
frame.filename_is_temporary = true
|
||||||
f.name_to_unlink = ""
|
f.name_to_unlink = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
100
tools/cmd/icat/transmit.go
Normal file
100
tools/cmd/icat/transmit.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
package icat
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"kitty/tools/tui/graphics"
|
||||||
|
"kitty/tools/utils/shm"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
func gc_for_image(imgd *image_data) *graphics.GraphicsCommand {
|
||||||
|
}
|
||||||
|
|
||||||
|
func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) error {
|
||||||
|
var data_size int
|
||||||
|
if frame.in_memory_bytes == nil {
|
||||||
|
f, err := os.Open(frame.filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
sz, _ := f.Seek(0, io.SeekEnd)
|
||||||
|
f.Seek(0, io.SeekStart)
|
||||||
|
mmap, err := shm.CreateTemp("icat-*", uint64(sz))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer mmap.Close()
|
||||||
|
dest := mmap.Slice()
|
||||||
|
for len(dest) > 0 {
|
||||||
|
n, err := f.Read(dest)
|
||||||
|
dest = dest[n:]
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mmap.Unlink()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data_size = len(mmap.Slice()) - len(dest)
|
||||||
|
} else {
|
||||||
|
mmap, err := shm.CreateTemp("icat-*", uint64(len(frame.in_memory_bytes)))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer mmap.Close()
|
||||||
|
data_size = copy(mmap.Slice(), frame.in_memory_bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func transmit_file(imgd *image_data, frame_num int, frame *image_frame) error {
|
||||||
|
}
|
||||||
|
|
||||||
|
func transmit_stream(imgd *image_data, frame_num int, frame *image_frame) error {
|
||||||
|
}
|
||||||
|
|
||||||
|
func transmit_image(imgd *image_data) {
|
||||||
|
defer func() {
|
||||||
|
for _, frame := range imgd.frames {
|
||||||
|
if frame.filename_is_temporary && frame.filename != "" {
|
||||||
|
os.Remove(frame.filename)
|
||||||
|
frame.filename = ""
|
||||||
|
}
|
||||||
|
frame.in_memory_bytes = nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var f func(*image_data, int, *image_frame) error
|
||||||
|
if opts.TransferMode != "detect" {
|
||||||
|
switch opts.TransferMode {
|
||||||
|
case "file":
|
||||||
|
f = transmit_file
|
||||||
|
case "memory":
|
||||||
|
f = transmit_shm
|
||||||
|
case "stream":
|
||||||
|
f = transmit_stream
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f == nil && transfer_by_memory == supported && imgd.frames[0].in_memory_bytes != nil {
|
||||||
|
f = transmit_shm
|
||||||
|
}
|
||||||
|
if f == nil && transfer_by_file == supported {
|
||||||
|
f = transmit_file
|
||||||
|
}
|
||||||
|
if f == nil {
|
||||||
|
f = transmit_stream
|
||||||
|
}
|
||||||
|
for frame_num, frame := range imgd.frames {
|
||||||
|
err := f(imgd, frame_num, &frame)
|
||||||
|
if err != nil {
|
||||||
|
print_error("Failed to transmit %s with error: %v", imgd.source_name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user