richterm

"terminal emulator" with support for text fonts and images for plan9
git clone git://nsmpr.xyz/richterm.git
Log | Files | Refs | README

commit cf702fcdf9776c99c52b6ad945ea4e166a276bee
parent b1172113893fc77e2f8174c6e55bc19583d5272d
Author: Pavel Renev <an2qzavok@gmail.com>
Date:   Sat, 28 Aug 2021 21:57:29 +0000

accept into files and write images

Diffstat:
MTODO | 21++++++++++++++++++---
Mfs.c | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mrichterm.c | 19+++++++++++++++----
3 files changed, 184 insertions(+), 34 deletions(-)

diff --git a/TODO b/TODO @@ -1,8 +1,23 @@ # images -draw them +something in image drawing routines is broken, not handling it well when +image's rectangle.min != ZP. -# links +# fs_flush -highlight them and add 3-button menu for interacting with them +We need to prevent server from locking up. +See 9pqueue(2) + +I think I need an independent queue for every blocking file. + +# fix crashes + +when you write into files, also related to file trunkating. + +# simplify file handling + +Add Array for text to objects, and use standard arrayread/arraywrite. +Copy array back to global text buffer on destroyfid + +Do the same for fonts. diff --git a/fs.c b/fs.c @@ -8,27 +8,33 @@ #include "array.h" #include "richterm.h" -File *new, *ctl, *text, *cons, *consctl, *menu; -Object *newobj; -File *fsroot; -Channel *consc, *ctlc; Array *consbuf, *ctlbuf, *menubuf; +Channel *consc, *ctlc; +File *fsroot; +File *cons, *consctl, *ctl, *menu, *new, *text; +Object *newobj; +Reqqueue *rq; + -void fs_open(Req *); -void fs_read(Req *); -void fs_write(Req *); -void ftree_destroy(File *); -char * textread(Req *); -char * textwrite(Req *); char * arrayread(Req *); char * arraywrite(Req *); -char * fontread(Req *); -char * fontwrite(Req *); char * consread(Req *); char * conswrite(Req *); char * ctlread(Req *); char * ctlwrite(Req *); +char * fontread(Req *); +char * fontwrite(Req *); char * newread(Req *); +char * textread(Req *); +char * textwrite(Req *); +void delayedread(Req *); +void fs_destroyfid(Fid *); +void fs_flush(Req *); +void fs_open(Req *); +void fs_read(Req *); +void fs_write(Req *); +void imageclose(Fid *); + int initfs(char *srvname) @@ -37,9 +43,12 @@ initfs(char *srvname) .open = fs_open, .read = fs_read, .write = fs_write, + .flush = fs_flush, + .destroyfid = fs_destroyfid, }; newobj = nil; consbuf = nil; + rq = reqqueuecreate(); menubuf = arraycreate(sizeof(char), 1024, nil); consc = chancreate(sizeof(Array *), 1024); ctlc = chancreate(sizeof(Array *), 1024); @@ -145,16 +154,30 @@ ctlcmd(char *buf) return nil; } + +void +fs_destroyfid(Fid *fid) +{ + if (fid->file == nil) return; + if (fid->file->aux == nil) return; + if (((Faux *)fid->file->aux)->obj == nil) return; + if (((Faux *)fid->file->aux)->obj->fimage == nil) return; + if (fid->file == ((Faux *)fid->file->aux)->obj->fimage) { + imageclose(fid); + } +} + void fs_open(Req *r) { + if (r->fid->omode && OTRUNC) { +// if ((r->fid->file->aux != nil) && (((Faux *)r->fid->file->aux)->data != nil)) +// ((Faux *)r->fid->file->aux)->data->count = 0; + } if (r->fid->file == new) { newobj = objectcreate(); mkobjectftree(newobj, fsroot); objinsertbeforelast(newobj); - - /* Because our newobj is created empty, there's no need - to move text from olast around. */ } respond(r, nil); } @@ -162,14 +185,7 @@ fs_open(Req *r) void fs_read(Req *r) { - Faux *aux; - char *s; - aux = r->fid->file->aux; - if (aux != nil) { - if (aux->read != nil) s = aux->read(r); - else s = "no read"; - } else s = "fs_read: f->aux is nil"; - respond(r, s); + reqqueuepush(rq, r, delayedread); } void @@ -188,6 +204,25 @@ fs_write(Req *r) respond(r, s); } +void +fs_flush(Req *r) +{ + respond(r, nil); +} + +void +delayedread(Req *r) +{ + Faux *aux; + char *s; + aux = r->fid->file->aux; + if (aux != nil) { + if (aux->read != nil) s = aux->read(r); + else s = "no read"; + } else s = "fs_read: f->aux is nil"; + respond(r, s); +} + char * arrayread(Req *r) { @@ -204,12 +239,21 @@ arrayread(Req *r) char * arraywrite(Req *r) { + long count; Array *data; - data = ((Faux *)r->fid->file->aux)->data; qlock(rich.l); - data->count = 0; - arraygrow(data, r->ifcall.count, r->ifcall.data); + data = ((Faux *)r->fid->file->aux)->data; + count = r->ifcall.count + r->ifcall.offset; + if (count > data->count) arraygrow(data, count - data->count, nil); + else data->count = count; + +// data->count = 0; +// arraygrow(data, r->ifcall.count, r->ifcall.data); + qlock(data->l); + memcpy(data->p + r->ifcall.offset, r->ifcall.data, r->ifcall.count); + qunlock(data->l); r->ofcall.count = r->ifcall.count; + r->fid->file->length = data->count; qunlock(rich.l); return nil; } @@ -236,6 +280,8 @@ textread(Req *r) readbuf(r, s, n - obj->offset); + r->fid->file->length = objtextlen(obj); + qunlock(rich.text->l); qunlock(rich.l); return nil; @@ -325,7 +371,7 @@ conswrite(Req *r) Array *a; a = arraycreate(sizeof(char), r->ifcall.count, nil); arraygrow(a, r->ifcall.count, r->ifcall.data); - send(insertc, &a); + nbsend(insertc, &a); r->ofcall.count = r->ifcall.count; return nil; } @@ -363,3 +409,81 @@ newread(Req *r) readstr(r, newobj->id); return nil; } + +void +imageclose(Fid *fid) +{ + Array *data; + Rectangle r; + char *p; + int compressed, m; + long n; + ulong chan; + Faux *aux; + + + compressed = 0; + aux = fid->file->aux; + data = aux->data; + + if (aux->obj->image != nil) return; + + qlock(data->l); + p = data->p; + n = data->count; + if (n < 10) { + data->count = 0; + aux->obj->ftext->length = 0; + qunlock(data->l); + fprint(2, "imageclose: image file too short\n"); + return; + } + if (strncmp("compressed\n", p, 11) == 0) { + p += 11; + n -= 11; + compressed = 1; + } + if (n < 60) { + data->count = 0; + aux->obj->ftext->length = 0; + qunlock(data->l); + fprint(2, "imageclose: image file too short\n"); + return; + } + if ((chan = strtochan(p)) == 0) { + data->count = 0; + aux->obj->ftext->length = 0; + qunlock(data->l); + fprint(2, "imageclose: image channel unknown: %12s\n", p); + return; + } + p += 12; n -= 12; + r.min.x = atoi(p); p += 12; n -= 12; + r.min.y = atoi(p); p += 12; n -= 12; + r.max.x = atoi(p); p += 12; n -= 12; + r.max.y = atoi(p); p += 12; n -= 12; + + lockdisplay(display); + aux->obj->image = allocimage(display, r, chan, 0, DBlue); + if (aux->obj->image == nil) { + data->count = 0; + aux->obj->ftext->length = 0; + qunlock(data->l); + unlockdisplay(display); + fprint(2, "imageclose: allocimage failed: %r\n"); + return; + } + if (compressed != 0) m = cloadimage(aux->obj->image, r, (uchar *)p, n); + else m = loadimage(aux->obj->image, r, (uchar *)p, n); + if (m != n) { + fprint(2, "imageclose: failed to load image\n"); + freeimage(aux->obj->image); + data->count = 0; + aux->obj->ftext->length = 0; + } + + unlockdisplay(display); + qunlock(data->l); + + return; +} diff --git a/richterm.c b/richterm.c @@ -649,14 +649,25 @@ drawobject(Object *obj, Point *cur) *cur = obj->prev->nextlinept; } - obj->startpt = *cur; - obj->nextlinept = Pt(0, cur->y + obj->font->height); + if ((obj->prev != nil) && (cur->x != 0)) { if (obj->nextlinept.y < obj->prev->nextlinept.y) obj->nextlinept.y = obj->prev->nextlinept.y; } + if (obj->image != nil) { + Rectangle r; + r = rectaddpt(obj->image->r, + subpt(addpt(*cur, rich.page.r.min), rich.page.scroll)); + draw(screen, r, obj->image, nil, ZP); + cur->x += Dx(r); + if (cur->y + Dy(r) > obj->nextlinept.y) + obj->nextlinept.y = cur->y + Dy(r); + } + + obj->startpt = *cur; + if (obj->next == nil) n = rich.text->count; else n = obj->next->offset; @@ -679,7 +690,6 @@ redraw(Object *) obj = nil; cur = ZP; qlock(rich.l); - for (i = 0; i < rich.objects->count; i++) { if (arrayget(rich.objects, i, &obj) == nil) sysfatal("redraw: %r"); @@ -803,6 +813,7 @@ objsettext(Object *obj, char *data, long count) qunlock(rich.text->l); qlock(rich.objects->l); + if (obj->ftext != nil) obj->ftext->length = count; for (obj = obj->next; obj != nil; obj = obj->next) { obj->offset += dn; } @@ -875,12 +886,12 @@ ruseract(int f) nbsend(ctlc, &a); } -char genbuf[1024]; char * rusergen(int f) { + static char genbuf[1024]; int i, k; char *ps, *pe; memset(genbuf, 0, sizeof(genbuf));