#include <u.h>
#include <libc.h>
#include <thread.h>
#include <fcall.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <frame.h>
#include <9p.h>
#include "gui.h"
#include "cook.h"
typedef struct Fent Fent;
struct Fent{
Font* font;
char* name;
};
static char* myaddr;
static void xinit(Panel*);
static void xterm(Panel*);
static long xread(Panel* p, void* buf, long cnt, vlong off);
static long xwrite(Panel* p, void* buf, long cnt, vlong off);
static void xdraw(Panel* p, int resize);
static void xmouse(Panel* p, Cmouse* m, Channel* mc);
static void xkeyboard(Panel*, Rune);
static void
binit(Panel*)
{
abort();
}
static void
bterm(Panel*)
{
abort();
}
static int
bctl(Panel*, char*)
{
abort();
return -1;
}
static long
battrs(Panel*, char*, long)
{
abort();
return -1;
}
static long
bread(Panel*, void*, long , vlong)
{
abort();
return -1;
}
static long
bwrite(Panel*, void*, long, vlong)
{
abort();
return -1;
}
static void
bdraw(Panel*, int)
{
abort();
}
static void
bmouse(Panel*, Cmouse*, Channel*)
{
abort();
}
static void
bkeyboard(Panel*, Rune)
{
abort();
}
Pops nilops = {
.pref = "/BUG/",
.init = binit,
.term = bterm,
.ctl = bctl,
.attrs= battrs,
.read = bread,
.write= bwrite,
.draw = bdraw,
.mouse = bmouse,
.keyboard = bkeyboard,
};
Pops rowops = {
.pref = "row:",
.init = xinit,
.term = xterm,
.ctl = genctl,
.attrs= genattrs,
.read = xread,
.write= xwrite,
.draw = xdraw,
.mouse = xmouse,
.keyboard = xkeyboard,
};
Pops colops = {
.pref = "col:",
.init = xinit,
.term = xterm,
.ctl = genctl,
.attrs= genattrs,
.read = xread,
.write= xwrite,
.draw = xdraw,
.mouse = xmouse,
.keyboard = xkeyboard,
};
static void
xdraw(Panel*, int)
{
}
static Font*
getfont(char* name)
{
switch(name[0]){
case 'R':
case 'r':
return fonts[FR];
case 'B':
case 'b':
return fonts[FB];
case 'L':
case 'l':
return fonts[FL];
case 'T':
case 't':
return fonts[FT];
case 'S':
case 's':
return fonts[FS];
default:
return nil;
}
}
static int
paneltype(char* name)
{
int i;
for (i = 0; panels[i] != nil; i++)
if (strstr(name, panels[i]->pref) == name)
return i;
return -1;
}
long
genreadbuf(void* data, long count, vlong off, void *s, long n)
{
long r;
r = count;
if(off >= n)
return 0;
if(off+r > n)
r = n - off;
memmove(data, (char*)s+off, r);
return r;
}
static long
xread(Panel*, void* , long , vlong )
{
return 0;
}
static long
xwrite(Panel*, void* , long , vlong )
{
return 0;
}
static void
xmouse(Panel* p, Cmouse* m, Channel* mc)
{
tagmousecmd(p->file, m, mc);
}
static void
xinit(Panel* p)
{
p->flags |= Ptag;
}
static void
xterm(Panel*)
{
}
static int
intagy(Panel* p, Point xy)
{
return xy.y >= p->rect.min.y &&
xy.y <= p->rect.min.y + 2 * Taght;
}
static void
xkeyboard(Panel* p, Rune r)
{
File* f;
f = p->file;
if (r == Kup || r == Kleft){
if (intagy(p, lastxy))
fullwin(f);
else
shiftsonsright(f);
resize();
} else if (r == Kdown || r == Kright){
if (intagy(p, lastxy))
incwin(f);
else
shiftsonsleft(f);
resize();
}
}
Panel*
newpanel(char* name, Panel* parent)
{
Panel* p;
int id;
id = paneltype(name);
if (id < 0){
werrstr("bad panel type");
return nil;
}
p = emalloc9p(sizeof(Panel));
memset(p, 0, sizeof(Panel));
p->ref = 1;
p->name = estrdup9p(name);
p->type = id;
p->atime = time(nil);
if (parent && parent->con){
incref(parent->con);
p->con = parent->con;
}
edprint("newpanel %p %s %d\n", p, p->name, p->type);
panels[id]->init(p);
return p;
}
void
closepanel(Panel* p)
{
extern File* focus;
if (p == nil)
return;
focus = nil;
p->flags |= Phide; // prevent redraws (paranoia).
edprint("closepanel %p %s %d\n", p, p->name, p->type);
panels[p->type]->term(p);
conprint(p->con, "%s exit\001", p->path);
free(p->name);
free(p->path);
closecon(p->con);
memset(p, 0, sizeof(*p)); // poison
free(p);
}
int
hidden(File* f)
{
Panel* p;
if (!f || !(f->qid.type&QTDIR) || !f->aux)
return 1;
p = f->aux;
if (p->flags&Phide)
return 1;
if (Dx(p->rect) <= 0 || Dy(p->rect) <= 0)
return 1;
if (f->parent == f || f->parent == nil)
return 0;
else
return hidden(f->parent);
}
void
rmhuppanels(File* f, Con* c)
{
File** w;
File** l;
File* fp;
Panel* p;
Panel* np;
p = f->aux;
if (p->con == c)
rmpanel(f);
else {
w = newfilewalk(f);
for (l = w; fp = *l; l++){
np = fp->aux;
if (np->con == c)
rmpanel(fp);
else if (np->type == Qcol || np->type == Qrow)
rmhuppanels(fp, c);
}
endfilewalk(w);
}
}
File*
pointinpanel(Point xy, int atomok)
{
File* f;
File* fp;
Panel* p;
Panel* np;
File** w;
File** l;
int nloop;
w = newfilewalk(slash);
f = w[0];
endfilewalk(w);
p = f->aux;
if (!ptinrect(xy, p->rect))
return f;
nloop = 0;
again:
assert(nloop++ < 50);
w = newfilewalk(f);
for (l = w; fp = *l; l++){
if (!ispanel(fp))
continue;
np = fp->aux;
if (np->flags&Phide)
continue;
if (ptinrect(xy, np->rect))
if (atomok || np->type == Qrow || np->type == Qcol){
f = fp;
endfilewalk(w);
goto again;
}
}
endfilewalk(w);
return f;
}
int
hastag(File*f)
{
Panel* p;
p = f->aux;
if (!strcmp(f->name, "/"))
return 0;
return (p->flags&Ptag);
}
File*
paneltop(File* f)
{
Panel* p;
for(;;){
p = f->aux;
if (p->flags&Ptop)
break;
if (p->flags&Playout)
break;
if (f == f->parent)
break;
f = f->parent;
}
assert(f && f->aux == p);
return f;
}
#include "/sys/src/lib9p/file.h"
/*
* Called once after each new panel.
* This minimizes all but the 2 MRU ones
* within the same container.
*/
void
cleanpolicy(File* f)
{
Panel* p;
File** w;
File** l;
Panel* np;
File* f0;
File* f1;
long t0, t1;
int somewants;
int now;
File* tf;
File* fp;
edprint("cleanpolicy for %s \n", f->name);
// 1. Locate top container.
tf = paneltop(f);
if (tf == tf->parent || tf->parent == slash)
return; // no clean at / or /sysnameui
else
f = tf;
p = f->aux;
// 2. Locate the two MRU ones (clumsy way to do it)
t0 = t1 = 0;
f0 = f1 = nil;
somewants = 0;
if (0 && f->filelist->f)
print("f %p ref %ld 1st %p ref %ld\n", f, f->ref, f->filelist->f, f->filelist->f->ref);
w = newfilewalk(f);
for (l = w; fp = *l; l++){
if (!ispanel(fp))
continue;
np = fp->aux;
edprint("\t %s\t%ld at %x flags %d wx %d wy\n",
fp->name, np->atime, np->flags, np->wants.x, np->wants.y);
if (np->flags&Phide)
continue;
if (np->type != Qcol && np->type != Qrow)
continue;
if (p->type == Qcol && np->wants.y)
somewants++;
if (p->type == Qrow && np->wants.x)
somewants++;
if (t0 < np->atime){
t0 = np->atime;
f0 = fp;
}
}
if (0 && f->filelist->f)
print("e %p %s ref %ld 1st %p ref %ld\n", f, f->name, f->ref, f->filelist->f, f->filelist->f->ref);
endfilewalk(w);
if (0 && f->filelist->f)
print("w %p ref %ld 1st %p ref %ld\n", f, f->ref, f->filelist->f, f->filelist->f->ref);
if (somewants < 1)
return;
w = newfilewalk(f);
for (l = w; fp = *l; l++){
if (!ispanel(fp))
continue;
np = fp->aux;
if (np->flags&Phide)
continue;
if (np->type != Qcol && np->type != Qrow)
continue;
if (t1 < np->atime && f0 != fp){
t1 = np->atime;
f1 = fp;
}
}
endfilewalk(w);
// 3. Minimize other ones.
edprint("=> f0 %s f1 %s\n", f0 ? f0->name : "nil", f1 ? f1->name : "nil");
now = time(nil);
w = newfilewalk(f);
for (l = w; fp = *l; l++){
if (!ispanel(fp))
continue;
np = fp->aux;
if (np->flags&Phide)
continue;
if (now - np->atime < 10)
continue;
// Experiment: keep rows as they are.
if (np->type != Qcol /* && np->type != Qrow */)
continue;
if (fp != f0 && fp != f1 && np->nwins != 1){
edprint("\tminwin %s\n", fp->name);
minwin(fp);
} else
edprint("\t nomin %s (%d nw)\n", fp->name, np->nwins);
}
endfilewalk(w);
}
void
setctlfilelen(Panel* p)
{
static char buf[200]; // it's not really used
p->cfile->length = panels[p->type]->attrs(p, buf, sizeof(buf));
}
/* Returns: -1 for bad ctl
* 1 if resize should be called.
* 0 otherwise
*/
int
genctl(Panel* p, char* op)
{
Font* f;
char* ea;
Panel* pfp;
int mustdraw;
edprint("%s: ctl: %s\n", p->name, op);
mustdraw = 0;
if (!strcmp(op, "hide") && !(p->flags&Ptop)){
if (!(p->flags&Phide)){
p->flags |= Phide;
pfp = p->file->parent->aux;
pfp->flags |= Pmore;
mustdraw = 1;
}
} else if (!strncmp(op, "show", 4)){
if (p->flags&Phide){
p->flags &= ~Phide;
p->flags |= Predraw;
pfp = p->file->parent->aux;
if (!hassons(p->file->parent, Phide))
pfp->flags &= ~Pmore;
mustdraw = 1;
}
} else if (!strncmp(op, "tag", 3) && !(p->flags&Playout)){
if (!(p->flags&Ptag)){
p->flags |= Ptag|Predraw;
mustdraw = 1;
}
} else if (!strncmp(op, "notag", 5) && !(p->flags&Playout)){
if (p->flags&Ptag){
p->flags &= ~Ptag;
p->flags |= Predraw;
mustdraw = 1;
}
} else if (!strncmp(op, "dirty", 5)){
if (!(p->flags&Pdirty)){
p->flags |= Pdirty;
borders(p->file->parent);
flushimage(display, 1);
}
} else if (!strncmp(op, "clean", 5)){
if (p->flags&Pdirty){
p->flags &= ~Pdirty;
borders(p->file->parent);
flushimage(display, 1);
}
} else if (!strncmp(op, "font ", 5)){
f = getfont(op+5);
if (f && f != p->font){
p->font = f;
p->flags |= Predraw;
mustdraw = 1;
}
} else if (!strncmp(op, "addr ", 5) && !(p->flags&Playout)){
closecon(p->con);
ea = strchr(op+5, ' ');
if (ea) *ea = 0;
p->con = newcon(op + 5);
setctlfilelen(p);
event(p, "addr /devs/%sui %s", sname, saddr);
} else if (!strcmp(op, "min")){
if (p->type == Qcol || p->type == Qrow){
p->nwins = 0;
minwin(p->file);
mustdraw = 1;
}
} else if (!strcmp(op, "nomin")){
if (p->type == Qcol || p->type == Qrow){
if (p->flags&Pmore){
fullwin(p->file);
mustdraw = 1;
}
}
} else if (!strncmp(op, "space ", 6)){
ea = strchr(op+6, ' ');
if (ea) *ea = 0;
p->space = atoi(op+6);
p->flags |= Predraw;
mustdraw = 1;
} else if (!strncmp(op, "size ", 5)){
; /* accepted, but ignored. To allow "cat ctl >.../ctl" */
} else {
werrstr("bad ctl: %s", op);
return -1;
}
setctlfilelen(p);
return mustdraw;
}
long
sprintattrs(Panel* p, char* str, long l, char* attr)
{
char* s;
if (l <= 0)
return -1;
s = str;
if (p->con)
s = seprint(s, str+l, "addr %-30s\n", p->con->addr);
if (p->flags&Ptag)
s = seprint(s, str+l, "tag \n");
else
s = seprint(s, str+l, "notag \n");
if (p->flags&Phide)
s = seprint(s, str+l, "hide \n");
else
s = seprint(s, str+l, "show \n");
if (p->flags&Pdirty)
s = seprint(s, str+l, "dirty \n");
else
s = seprint(s, str+l, "clean \n");
if (p->font == fonts[FL])
s = seprint(s, str+l, "font L\n");
else if (p->font == fonts[FR])
s = seprint(s, str+l, "font R\n");
else if (p->font == fonts[FB])
s = seprint(s, str+l, "font B\n");
else
s = seprint(s, str+l, "font T\n");
if (attr)
s = seprint(s, str+l, "%s", attr);
return s - str;
}
long
genattrs(Panel* p, char* str, long l)
{
return sprintattrs(p, str, l, nil);
}
int
genmouse(Panel* p, Cmouse* m, Channel* mc)
{
if (m->buttons == 4){
if (cookclick(m, mc))
event(p, "look %11d %s", strlen(p->name), p->name);
return 1;
} else if (m->buttons == 2){
if (cookclick(m, mc))
event(p, "exec %11d %s", strlen(p->name), p->name);
return 1;
} else
return 0;
}
void
showtree(File* f, int force)
{
Panel* p;
File** w;
File** l;
File* fp;
int forcethis;
if (f == nil || f->aux == nil)
return;
p = f->aux;
panelok(p);
if (p->flags&Pdead)
return;
forcethis = (p->flags&Predraw);
p->flags &= ~Predraw;
if (Dx(p->rect) <= 0 || Dy(p->rect) <= 0 || (p->flags&Phide))
return;
force |= (!eqrect(p->orect, p->rect));
ldprint("show: %s\t%R %d %d\n", f->name, p->rect, forcethis, force);
if (p->type == Qcol || p->type == Qrow){
w = newfilewalk(f);
for (l = w; fp = *l; l++)
if (ispanel(fp))
showtree(fp, force);
endfilewalk(w);
borders(f);
return;
}
if (force || forcethis){
panels[p->type]->draw(p, 1);
if (hastag(f))
drawtag(p, 0);
}
}
|