commit 6d6e7d80139ccfe54742096df8fa7f51f445c761
Author: glenda <glenda@9front.local>
Date: Tue, 28 Apr 2020 07:28:59 +0000
initial commit
Diffstat:
A | TODO | | | 5 | +++++ |
A | gophra.c | | | 448 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | mkfile | | | 9 | +++++++++ |
3 files changed, 462 insertions(+), 0 deletions(-)
diff --git a/TODO b/TODO
@@ -0,0 +1,5 @@
+* README
+* man page
+* git
+* history
+* image view
diff --git a/gophra.c b/gophra.c
@@ -0,0 +1,447 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <frame.h>
+
+enum {
+ DBorder = DBlue,
+ DWBG = DBlack,
+ DWFG = 0xCCCCCCFF,
+ DWFGL = DWhite,
+ DStatus = DYellow,
+};
+
+typedef struct Text Text;
+struct Text {
+ char *data;
+ long size;
+} text;
+
+Image *Iborder, *Iwbg, *Iwfg, *Iwfgl, *Istatus;
+
+Rectangle rstatus, rw;
+
+char status[256], path[256], addr[256], type;
+
+char history[64][256];
+int hc;
+
+char *tmpfile = "/tmp/gophra.tmp";
+
+long scroll;
+
+void usage(void);
+void back(void);
+void clear(void);
+void calcrects(void);
+void drawborder(void);
+void drawstatus(void);
+void drawtext(void);
+void drawmenu(void);
+int extracturl(char*);
+char* getline(long);
+void handlelink(void);
+int loadtext(char*, char*);
+void runhold(void*);
+void runpage(void*);
+int save(void);
+
+void
+threadmain(int argc, char **argv)
+{
+ Mousectl *mc;
+ Keyboardctl *kc;
+ Mouse mv;
+ Rune kv;
+ int rv[2];
+
+ long sline;
+ char *s;
+ int mpress;
+
+ ARGBEGIN{
+ default:
+ usage();
+ break;
+ }ARGEND;
+
+ if(initdraw(0, 0, "gophra") < 0)
+ sysfatal("inidraw failed: %r");
+
+ Iborder = allocimage(display, Rect(0,0,1,1),
+ RGB24, 1, DBorder);
+ Iwbg = allocimage(display, Rect(0,0,1,1),
+ RGB24, 1, DWBG);
+ Iwfg = allocimage(display, Rect(0,0,1,1),
+ RGB24, 1, DWFG);
+ Iwfgl = allocimage(display, Rect(0,0,1,1),
+ RGB24, 1, DWFGL);
+ Istatus = allocimage(display, Rect(0,0,1,1),
+ RGB24, 1, DStatus);
+
+ mpress = 0;
+ scroll = 0;
+ hc = 0;
+ snprint(status, 255, "gophra!");
+
+ if (argv[0] != 0) loadtext(argv[0], "");
+
+ calcrects();
+ drawborder();
+ drawstatus();
+ drawmenu();
+ flushimage(display, 1);
+
+ if((mc = initmouse(0, screen)) == nil)
+ sysfatal("initmouse failed: %r");
+ if((kc = initkeyboard(0)) == nil)
+ sysfatal("initkeyboard failed: %r");
+
+ Alt alts[4] = {
+ {kc->c, &kv, CHANRCV},
+ {mc->c, &mv, CHANRCV},
+ {mc->resizec, rv, CHANRCV},
+ {0, 0, CHANEND},
+ };
+
+ for (;;) {
+ switch (alt(alts)) {
+ case 0: /* keyboard */
+ if (kv == 0x7f) threadexitsall(nil);
+ if (kv == 'g') {
+ char buf[256];
+ buf[0] = 0;
+ if (enter("goto:", buf, 255, mc, kc, 0) >=0)
+ if (loadtext(buf, "") == 0){
+ drawmenu();
+ flushimage(display, 1);
+ }
+ }
+ break;
+ case 1: /* mouse */
+ if (ptinrect(mv.xy, rw) != 1) break;
+ if (mv.buttons == 0) mpress = 0;
+ if (mv.buttons == 8) {
+ mpress = 1;
+ scroll -= 1 + (mv.xy.y-rw.min.y)/font->height;
+ if (scroll < 0) scroll = 0;
+ drawmenu();
+ flushimage(display, 1);
+ }
+ if (mv.buttons == 16) {
+ mpress = 1;
+ scroll += 1 + (mv.xy.y-rw.min.y)/font->height;
+ drawmenu();
+ flushimage(display, 1);
+ }
+ if (mpress != 0) break;
+ if (mv.buttons == 1) {
+ mpress = 1;
+ sline = (mv.xy.y - rw.min.y) / font->height +
+ scroll;
+ s = getline(sline);
+ extracturl(s);
+ snprint(status, 255, "%s/%c%s", addr, type, path);
+ drawstatus();
+ flushimage(display, 1);
+ if (s != 0) free(s);
+ }
+ if (mv.buttons == 2) {
+ mpress = 1;
+ sline = (mv.xy.y - rw.min.y) / font->height +
+ scroll;
+ s = getline(sline);
+
+ handlelink();
+ if (s != 0) free(s);
+ }
+ break;
+ case 2: /* resize */
+ if(getwindow(display, Refnone) < 0)
+ sysfatal("resize failed: %r");
+ calcrects();
+ drawborder();
+ drawstatus();
+ drawmenu();
+ flushimage(display, 1);
+ break;
+ }
+ }
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s", argv0);
+ exits("usage");
+}
+
+void
+back(void)
+{
+ if (hc == 0) return;
+ hc--;
+ // todo: extract addr and path from history
+ //loadtext
+ drawmenu();
+ flushimage(display, 1);
+}
+
+void
+calcrects(void)
+{
+ rw = Rect(
+ screen->r.min.x + 4,
+ screen->r.min.y + 8 + font->height,
+ screen->r.max.x - 4,
+ screen->r.max.y - 4);
+ rstatus = Rect(
+ screen->r.min.x + 4,
+ screen->r.min.y + 4,
+ screen->r.max.x - 4,
+ screen->r.min.y + 4 + font->height);
+}
+
+void
+drawborder(void)
+{
+ draw(screen, screen->r, Iborder, 0, ZP);
+ draw(screen, rw, Iwbg, 0, ZP);
+}
+
+void
+drawstatus(void)
+{
+ draw(screen, rstatus, Iborder, 0, ZP);
+ string(screen, rstatus.min, Istatus, ZP, font, status);
+}
+
+void
+drawtext(void)
+{
+ char sbuf[1024], *tp, *sp;
+ long i;
+ int fflag;
+ Point dp;
+ fflag = 0;
+ dp = rw.min;
+ tp = text.data;
+ sp = sbuf;
+ draw(screen, rw, Iwbg, 0, ZP);
+ if (sp == nil) return;
+ while (tp < text.data + text.size) {
+ *sp = *tp;
+ sp++;
+ tp++;
+ if (*tp == '\n'){
+ *(sp-1) = 0;
+ fflag = 1;
+ }
+ if (dp.x + stringwidth(font, sbuf) > rw.max.x) {
+ *(sp-1) = 0;
+ tp--;
+ fflag = 1;
+ }
+ if (fflag) {
+ string(screen, dp, Iwfg, ZP, font, sbuf);
+ for (i = 0; i < 1024; i++) sbuf[i] = 0;
+ sp = sbuf;
+ dp.y += font->height;
+ if (dp.y + font->height > rw.max.y) break;
+ fflag = 0;
+ }
+ }
+}
+
+void
+drawmenu(void)
+{
+ char sbuf[1024], *tp, *sp;
+ Image *Ifg;
+ Point dp;
+ long n, lc;
+ lc = 0;
+ dp = rw.min;
+ tp = text.data;
+ sp = sbuf;
+ draw(screen, rw, Iwbg, 0, ZP);
+ if (sp == nil) return;
+ while (tp < text.data + text.size) {
+ *sp = *tp;
+ sp++;
+ tp++;
+ if (*tp == '\n'){
+ *sp = 0;
+ tp++;
+ lc++;
+ sp = sbuf;
+ if (lc-1 < scroll) continue;
+ n = strchr(sbuf, '\t') - (sbuf + 1);
+ while (dp.x + stringnwidth(font, sbuf+1, n) >
+ rw.max.x) n--;
+ Ifg = Iwfgl;
+ if (sbuf[0] == 'i') Ifg = Iwfg;
+ stringn(screen, dp, Ifg, ZP, font, sbuf+1, n);
+ dp.y += font->height;
+ if (dp.y + font->height > rw.max.y) break;
+ }
+ }
+ if ((tp >= text.data + text.size) && (scroll > lc))
+ scroll = lc;
+}
+
+char*
+getline(long ln)
+{
+ char *sbuf, *sp, *tp;
+ long lc;
+ sbuf = malloc(sizeof(char) * 1024);
+ sp = sbuf;
+ tp = text.data;
+ for (lc = 0; lc < ln; tp++) {
+ if (*tp == '\n') lc++;
+ if (tp > text.data + text.size) return 0;
+ }
+ while (*tp != '\n') {
+ *sp = *tp;
+ sp++;
+ *sp = 0;
+ tp++;
+ if (tp > text.data + text.size) return 0;
+ }
+ return sbuf;
+}
+
+int
+extracturl(char *s)
+{
+ char *sp, *ep, buf[1024], port[256];
+ type = s[0];
+ sp = strchr(s, '\t') + 1;
+ ep = strchr(sp, '\t');
+ strncpy(path, sp, ep-sp);
+ path[ep-sp] = 0;
+ sp = ep + 1;
+ ep = strchr(sp, '\t');
+ buf[0] = 0;
+ strncpy(buf, sp, ep-sp);
+ buf[ep-sp] = 0;
+ sp = ep + 1;
+ ep = strchr(sp, '\r');
+ strncpy(port, sp, ep-sp);
+ port[ep-sp] = 0;
+ snprint(addr, 1024, "tcp!%s!%s", buf, port);
+ return 0;
+}
+
+void
+handlelink(void)
+{
+ switch (type) {
+ case '0':
+ save();
+ proccreate(runhold, 0, 1024 * 8);
+ break;
+ case '1':
+ loadtext(addr, path);
+ scroll = 0;
+ drawmenu();
+ flushimage(display, 1);
+ break;
+ case 'I':
+ save();
+ proccreate(runpage, 0, 1024 * 8);
+ break;
+ default:
+ snprint(status, 255, "unknown type - %c", type);
+ drawstatus();
+ flushimage(display, 1);
+ }
+}
+
+int
+loadtext(char *addr, char *path)
+{
+ int dcfd;
+ long n;
+ char buf[1024];
+
+ dcfd = dial(addr, 0, 0, 0);
+ if (dcfd > 0) {
+ write(dcfd, path, strlen(path));
+ write(dcfd, "\n", 1);
+ } else {
+ snprint(status, 255, "failed to dial %s", addr);
+ drawstatus();
+ flushimage(display, 1);
+ return -1;
+ }
+
+ text.size = 0;
+ while ((n = read(dcfd, buf, 1024)) > 0) {
+ text.data = realloc(text.data, text.size + n);
+ memcpy(text.data + text.size, buf, n);
+ text.size += n;
+ snprint(status, 255, "loading %s: %ldB", path, text.size);
+ drawstatus();
+ flushimage(display, 1);
+ }
+ snprint(status, 255, "done");
+ drawstatus();
+ flushimage(display, 1);
+ return 0;
+}
+
+
+void
+runhold(void*)
+{
+ // TODO: this should be done through plumber
+ procexecl(nil, "/bin/window", "window", "-m", "hold", tmpfile, nil);
+}
+
+void
+runpage(void*)
+{
+ procexecl(nil, "/bin/window", "window", "-m", "page", tmpfile, nil);
+}
+
+int
+save(void)
+{
+ int dcfd, wfd;
+ long n;
+ char buf[1024];
+
+ dcfd = dial(addr, 0, 0, 0);
+ if (dcfd > 0) {
+ write(dcfd, path, strlen(path));
+ write(dcfd, "\n", 1);
+ } else {
+ snprint(status, 255, "failed to dial %s", addr);
+ drawstatus();
+ flushimage(display, 1);
+ return -1;
+ }
+
+ wfd = create(tmpfile, OWRITE, 0666);
+ if (wfd <= 0) {
+ snprint(status, 255, "failed to create tmpfile");
+ drawstatus();
+ flushimage(display, 1);
+ return -1;
+ }
+ while ((n = read(dcfd, buf, 1024)) > 0) {
+ write(wfd, buf, n);
+ }
+ close(dcfd);
+ close(wfd);
+ snprint(status, 255, "saved");
+ drawstatus();
+ flushimage(display, 1);
+ return 0;
+}
+\ No newline at end of file
diff --git a/mkfile b/mkfile
@@ -0,0 +1,8 @@
+</$objtype/mkfile
+BIN=/$objtype/bin
+
+TARG=gophra
+
+OFILES=gophra.$O
+
+</sys/src/cmd/mkone
+\ No newline at end of file