/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <draw.h>#include <thread.h>#include <cursor.h>#include <mouse.h>#include <keyboard.h>#include <frame.h>#include <fcall.h>#include <plumb.h>#include "dat.h"#include "fns.h" /* * WASHINGTON (AP) - The Food and Drug Administration warned * consumers Wednesday not to use ``Rio'' hair relaxer products * because they may cause severe hair loss or turn hair green.... * The FDA urged consumers who have experienced problems with Rio * to notify their local FDA office, local health department or the * company at 1‑800‑543‑3002. */ void resize(void);void move(void);void delete(void);void hide(void);void unhide(int);void newtile(int);Image *sweep(void);Image *bandsize(Window*);Image* drag(Window*, Rectangle*);void refresh(Rectangle);void resized(void);Channel *exitchan; /* chan(int) */Channel *winclosechan; /* chan(Window*); */Rectangle viewr;int threadrforkflag = 0; /* should be RFENVG but that hides rio from plumber */ void mousethread(void*);void keyboardthread(void*);void winclosethread(void*);void deletethread(void*);void initcmd(void*); char *fontname;int mainpid; enum{ New, Reshape, Move, Delete, Hide, Exit,}; enum{ Cut, Paste, Snarf, Plumb, Send, Scroll,}; char *menu2str[] = { [Cut] "cut", [Paste] "paste", [Snarf] "snarf", [Plumb] "plumb", [Send] "send", [Scroll] "scroll", nil}; Menu menu2 ={ menu2str}; int Hidden = Exit+1; char *menu3str[100] = { [New] "New", [Reshape] "Resize", [Move] "Move", [Delete] "Delete", [Hide] "Hide", [Exit] "Exit", nil}; Menu menu3 ={ menu3str}; char *rcargv[] = { "rc", "-i", nil };char *kbdargv[] = { "rc", "-c", nil, nil }; int errorshouldabort = 0; voidderror(Display*, char *errorstr){ error(errorstr);} voidusage(void){ fprint(2, "usage: rio [-f font] [-i initcmd] [-k kbdcmd] [-s]\n"); exits("usage");} voidthreadmain(int argc, char *argv[]){ char *initstr, *kbdin, *s; static void *arg[1]; char buf[256]; Image *i; Rectangle r; if(strstr(argv[0], ".out") == nil){ menu3str[Exit] = nil; Hidden--; } initstr = nil; kbdin = nil; maxtab = 0; ARGBEGIN{ case 'f': fontname = ARGF(); if(fontname == nil) usage(); break; case 'i': initstr = ARGF(); if(initstr == nil) usage(); break; case 'k': if(kbdin != nil) usage(); kbdin = ARGF(); if(kbdin == nil) usage(); break; case 's': scrolling = TRUE; break; }ARGEND mainpid = getpid(); if(getwd(buf, sizeof buf) == nil) startdir = estrdup("."); else startdir = estrdup(buf); if(fontname == nil) fontname = getenv("font"); if(fontname == nil) fontname = "/lib/font/bit/lucm/unicode.9.font"; s = getenv("tabstop"); if(s != nil) maxtab = strtol(s, nil, 0); if(maxtab == 0) maxtab = 4; free(s); /* check font before barging ahead */ if(access(fontname, 0) < 0){ fprint(2, "rio: can't access %s: %r\n", fontname); exits("font open"); } putenv("font", fontname); snarffd = open("/dev/snarf", OREAD|OCEXEC); if(geninitdraw(nil, derror, nil, "rio", nil, Refnone) < 0){ fprint(2, "rio: can't open display: %r\n"); exits("display open"); } iconinit(); view = screen; viewr = view->r; mousectl = initmouse(nil, screen); if(mousectl == nil) error("can't find mouse"); mouse = mousectl; keyboardctl = initkeyboard(nil); if(keyboardctl == nil) error("can't find keyboard"); wscreen = allocscreen(screen, background, 0); if(wscreen == nil) error("can't allocate screen"); draw(view, viewr, background, nil, ZP); flushimage(display, 1); exitchan = chancreate(sizeof(int), 0); winclosechan = chancreate(sizeof(Window*), 0); deletechan = chancreate(sizeof(char*), 0); timerinit(); threadcreate(keyboardthread, nil, STACK); threadcreate(mousethread, nil, STACK); threadcreate(winclosethread, nil, STACK); threadcreate(deletethread, nil, STACK); filsys = filsysinit(xfidinit()); if(filsys == nil) fprint(2, "rio: can't create file system server: %r\n"); else{ errorshouldabort = 1; /* suicide if there's trouble after this */ if(initstr) proccreate(initcmd, initstr, STACK); if(kbdin){ kbdargv[2] = kbdin; r = screen->r; r.max.x = r.min.x+300; r.max.y = r.min.y+80; i = allocwindow(wscreen, r, Refbackup, DWhite); wkeyboard = new(i, FALSE, scrolling, 0, nil, "/bin/rc", kbdargv); if(wkeyboard == nil) error("can't create keyboard window"); } threadnotify(shutdown, 1); recv(exitchan, nil); } killprocs(); threadexitsall(nil);} /* * /dev/snarf updates when the file is closed, so we must open our own * fd here rather than use snarffd */voidputsnarf(void){ int fd, i, n; if(snarffd<0 || nsnarf==0) return; fd = open("/dev/snarf", OWRITE); if(fd < 0) return; /* snarf buffer could be huge, so fprint will truncate; do it in blocks */ for(i=0; i<nsnarf; i+=n){ n = nsnarf-i; if(n >= 256) n = 256; if(fprint(fd, "%.*S", n, snarf+i) < 0) break; } close(fd);} voidgetsnarf(void){ int i, n, nb, nulls; char *sn, buf[1024]; if(snarffd < 0) return; sn = nil; i = 0; seek(snarffd, 0, 0); while((n = read(snarffd, buf, sizeof buf)) > 0){ sn = erealloc(sn, i+n+1); memmove(sn+i, buf, n); i += n; sn[i] = 0; } if(i > 0){ snarf = runerealloc(snarf, i+1); cvttorunes(sn, i, snarf, &nb, &nsnarf, &nulls); free(sn); }} voidinitcmd(void *arg){ char *cmd; cmd = arg; rfork(RFENVG|RFFDG|RFNOTEG|RFNAMEG); procexecl(nil, "/bin/rc", "rc", "-c", cmd, nil); fprint(2, "rio: exec failed: %r\n"); exits("exec");} char *oknotes[] ={ "delete", "hangup", "kill", "exit", nil}; intshutdown(void *, char *msg){ int i; static Lock shutdownlk; killprocs(); for(i=0; oknotes[i]; i++) if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0){ lock(&shutdownlk); /* only one can threadexitsall */ threadexitsall(msg); } fprint(2, "rio %d: abort: %s\n", getpid(), msg); abort(); exits(msg); return 0;} voidkillprocs(void){ int i; for(i=0; i<nwindow; i++) postnote(PNGROUP, window[i]->pid, "hangup");} voidkeyboardthread(void*){ Rune buf[2][20], *rp; int n, i; threadsetname("keyboardthread"); n = 0; for(;;){ rp = buf[n]; n = 1-n; recv(keyboardctl->c, rp); for(i=1; i<nelem(buf[0])-1; i++) if(nbrecv(keyboardctl->c, rp+i) <= 0) break; rp[i] = L'\0'; if(input != nil) sendp(input->ck, rp); }} /* * Used by /dev/kbdin */voidkeyboardsend(char *s, int cnt){ Rune *r; int i, nb, nr; r = runemalloc(cnt); /* BUGlet: partial runes will be converted to error runes */ cvttorunes(s, cnt, r, &nb, &nr, nil); for(i=0; i<nr; i++) send(keyboardctl->c, &r[i]); free(r);} intportion(int x, int lo, int hi){ x -= lo; hi -= lo; if(x < 20) return 0; if(x > hi-20) return 2; return 1;} intwhichcorner(Window *w, Point p){ int i, j; i = portion(p.x, w->screenr.min.x, w->screenr.max.x); j = portion(p.y, w->screenr.min.y, w->screenr.max.y); return 3*j+i;} voidcornercursor(Window *w, Point p, int force){ if(w!=nil && winborder(w, p)) riosetcursor(corners[whichcorner(w, p)], force); else wsetcursor(w, force);} /* thread to allow fsysproc to synchronize window closing with main proc */voidwinclosethread(void*){ Window *w; threadsetname("winclosethread"); for(;;){ w = recvp(winclosechan); wclose(w); }} /* thread to make Deleted windows that the client still holds disappear offscreen after an interval */voiddeletethread(void*){ char *s; Image *i; threadsetname("deletethread"); for(;;){ s = recvp(deletechan); i = namedimage(display, s); if(i != nil){ /* move it off-screen to hide it, since client is slow in letting it go */ originwindow(i, i->r.min, view->r.max); } freeimage(i); free(s); }} voiddeletetimeoutproc(void *v){ char *s; s = v; sleep(750); /* remove window from screen after 3/4 of a second */ sendp(deletechan, s);} /* * Button 6 - keyboard toggle - has been pressed. * Send event to keyboard, wait for button up, send that. * Note: there is no coordinate translation done here; this * is just about getting button 6 to the keyboard simulator. */voidkeyboardhide(void){ send(wkeyboard->mc.c, mouse); do readmouse(mousectl); while(mouse->buttons & (1<<5)); send(wkeyboard->mc.c, mouse);} voidmousethread(void*){ int sending, inside, scrolling, moving, band; Window *oin, *w, *winput; Image *i; Rectangle r; Point xy; Mouse tmp; enum { MReshape, MMouse, NALT }; static Alt alts[NALT+1]; threadsetname("mousethread"); sending = FALSE; scrolling = FALSE; moving = FALSE; alts[MReshape].c = mousectl->resizec; alts[MReshape].v = nil; alts[MReshape].op = CHANRCV; alts[MMouse].c = mousectl->c; alts[MMouse].v = &mousectl->Mouse; alts[MMouse].op = CHANRCV; alts[NALT].op = CHANEND; for(;;) switch(alt(alts)){ case MReshape:Lines 1–500 of 1200. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <draw.h> #include <thread.h> #include <cursor.h> #include <mouse.h> #include <keyboard.h> #include <frame.h> #include <fcall.h> #include <plumb.h> #include "dat.h" #include "fns.h" /* * WASHINGTON (AP) - The Food and Drug Administration warned * consumers Wednesday not to use ``Rio'' hair relaxer products * because they may cause severe hair loss or turn hair green.... * The FDA urged consumers who have experienced problems with Rio * to notify their local FDA office, local health department or the * company at 1‑800‑543‑3002. */ void resize(void); void move(void); void delete(void); void hide(void); void unhide(int); void newtile(int); Image *sweep(void); Image *bandsize(Window*); Image* drag(Window*, Rectangle*); void refresh(Rectangle); void resized(void); Channel *exitchan; /* chan(int) */ Channel *winclosechan; /* chan(Window*); */ Rectangle viewr; int threadrforkflag = 0; /* should be RFENVG but that hides rio from plumber */ void mousethread(void*); void keyboardthread(void*); void winclosethread(void*); void deletethread(void*); void initcmd(void*); char *fontname; int mainpid; enum { New, Reshape, Move, Delete, Hide, Exit, }; enum { Cut, Paste, Snarf, Plumb, Send, Scroll, }; char *menu2str[] = { [Cut] "cut", [Paste] "paste", [Snarf] "snarf", [Plumb] "plumb", [Send] "send", [Scroll] "scroll", nil }; Menu menu2 = { menu2str }; int Hidden = Exit+1; char *menu3str[100] = { [New] "New", [Reshape] "Resize", [Move] "Move", [Delete] "Delete", [Hide] "Hide", [Exit] "Exit", nil }; Menu menu3 = { menu3str }; char *rcargv[] = { "rc", "-i", nil }; char *kbdargv[] = { "rc", "-c", nil, nil }; int errorshouldabort = 0; void derror(Display*, char *errorstr) { error(errorstr); } void usage(void) { fprint(2, "usage: rio [-f font] [-i initcmd] [-k kbdcmd] [-s]\n"); exits("usage"); } void threadmain(int argc, char *argv[]) { char *initstr, *kbdin, *s; static void *arg[1]; char buf[256]; Image *i; Rectangle r; if(strstr(argv[0], ".out") == nil){ menu3str[Exit] = nil; Hidden--; } initstr = nil; kbdin = nil; maxtab = 0; ARGBEGIN{ case 'f': fontname = ARGF(); if(fontname == nil) usage(); break; case 'i': initstr = ARGF(); if(initstr == nil) usage(); break; case 'k': if(kbdin != nil) usage(); kbdin = ARGF(); if(kbdin == nil) usage(); break; case 's': scrolling = TRUE; break; }ARGEND mainpid = getpid(); if(getwd(buf, sizeof buf) == nil) startdir = estrdup("."); else startdir = estrdup(buf); if(fontname == nil) fontname = getenv("font"); if(fontname == nil) fontname = "/lib/font/bit/lucm/unicode.9.font"; s = getenv("tabstop"); if(s != nil) maxtab = strtol(s, nil, 0); if(maxtab == 0) maxtab = 4; free(s); /* check font before barging ahead */ if(access(fontname, 0) < 0){ fprint(2, "rio: can't access %s: %r\n", fontname); exits("font open"); } putenv("font", fontname); snarffd = open("/dev/snarf", OREAD|OCEXEC); if(geninitdraw(nil, derror, nil, "rio", nil, Refnone) < 0){ fprint(2, "rio: can't open display: %r\n"); exits("display open"); } iconinit(); view = screen; viewr = view->r; mousectl = initmouse(nil, screen); if(mousectl == nil) error("can't find mouse"); mouse = mousectl; keyboardctl = initkeyboard(nil); if(keyboardctl == nil) error("can't find keyboard"); wscreen = allocscreen(screen, background, 0); if(wscreen == nil) error("can't allocate screen"); draw(view, viewr, background, nil, ZP); flushimage(display, 1); exitchan = chancreate(sizeof(int), 0); winclosechan = chancreate(sizeof(Window*), 0); deletechan = chancreate(sizeof(char*), 0); timerinit(); threadcreate(keyboardthread, nil, STACK); threadcreate(mousethread, nil, STACK); threadcreate(winclosethread, nil, STACK); threadcreate(deletethread, nil, STACK); filsys = filsysinit(xfidinit()); if(filsys == nil) fprint(2, "rio: can't create file system server: %r\n"); else{ errorshouldabort = 1; /* suicide if there's trouble after this */ if(initstr) proccreate(initcmd, initstr, STACK); if(kbdin){ kbdargv[2] = kbdin; r = screen->r; r.max.x = r.min.x+300; r.max.y = r.min.y+80; i = allocwindow(wscreen, r, Refbackup, DWhite); wkeyboard = new(i, FALSE, scrolling, 0, nil, "/bin/rc", kbdargv); if(wkeyboard == nil) error("can't create keyboard window"); } threadnotify(shutdown, 1); recv(exitchan, nil); } killprocs(); threadexitsall(nil); } /* * /dev/snarf updates when the file is closed, so we must open our own * fd here rather than use snarffd */ void putsnarf(void) { int fd, i, n; if(snarffd<0 || nsnarf==0) return; fd = open("/dev/snarf", OWRITE); if(fd < 0) return; /* snarf buffer could be huge, so fprint will truncate; do it in blocks */ for(i=0; i<nsnarf; i+=n){ n = nsnarf-i; if(n >= 256) n = 256; if(fprint(fd, "%.*S", n, snarf+i) < 0) break; } close(fd); } void getsnarf(void) { int i, n, nb, nulls; char *sn, buf[1024]; if(snarffd < 0) return; sn = nil; i = 0; seek(snarffd, 0, 0); while((n = read(snarffd, buf, sizeof buf)) > 0){ sn = erealloc(sn, i+n+1); memmove(sn+i, buf, n); i += n; sn[i] = 0; } if(i > 0){ snarf = runerealloc(snarf, i+1); cvttorunes(sn, i, snarf, &nb, &nsnarf, &nulls); free(sn); } } void initcmd(void *arg) { char *cmd; cmd = arg; rfork(RFENVG|RFFDG|RFNOTEG|RFNAMEG); procexecl(nil, "/bin/rc", "rc", "-c", cmd, nil); fprint(2, "rio: exec failed: %r\n"); exits("exec"); } char *oknotes[] = { "delete", "hangup", "kill", "exit", nil }; int shutdown(void *, char *msg) { int i; static Lock shutdownlk; killprocs(); for(i=0; oknotes[i]; i++) if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0){ lock(&shutdownlk); /* only one can threadexitsall */ threadexitsall(msg); } fprint(2, "rio %d: abort: %s\n", getpid(), msg); abort(); exits(msg); return 0; } void killprocs(void) { int i; for(i=0; i<nwindow; i++) postnote(PNGROUP, window[i]->pid, "hangup"); } void keyboardthread(void*) { Rune buf[2][20], *rp; int n, i; threadsetname("keyboardthread"); n = 0; for(;;){ rp = buf[n]; n = 1-n; recv(keyboardctl->c, rp); for(i=1; i<nelem(buf[0])-1; i++) if(nbrecv(keyboardctl->c, rp+i) <= 0) break; rp[i] = L'\0'; if(input != nil) sendp(input->ck, rp); } } /* * Used by /dev/kbdin */ void keyboardsend(char *s, int cnt) { Rune *r; int i, nb, nr; r = runemalloc(cnt); /* BUGlet: partial runes will be converted to error runes */ cvttorunes(s, cnt, r, &nb, &nr, nil); for(i=0; i<nr; i++) send(keyboardctl->c, &r[i]); free(r); } int portion(int x, int lo, int hi) { x -= lo; hi -= lo; if(x < 20) return 0; if(x > hi-20) return 2; return 1; } int whichcorner(Window *w, Point p) { int i, j; i = portion(p.x, w->screenr.min.x, w->screenr.max.x); j = portion(p.y, w->screenr.min.y, w->screenr.max.y); return 3*j+i; } void cornercursor(Window *w, Point p, int force) { if(w!=nil && winborder(w, p)) riosetcursor(corners[whichcorner(w, p)], force); else wsetcursor(w, force); } /* thread to allow fsysproc to synchronize window closing with main proc */ void winclosethread(void*) { Window *w; threadsetname("winclosethread"); for(;;){ w = recvp(winclosechan); wclose(w); } } /* thread to make Deleted windows that the client still holds disappear offscreen after an interval */ void deletethread(void*) { char *s; Image *i; threadsetname("deletethread"); for(;;){ s = recvp(deletechan); i = namedimage(display, s); if(i != nil){ /* move it off-screen to hide it, since client is slow in letting it go */ originwindow(i, i->r.min, view->r.max); } freeimage(i); free(s); } } void deletetimeoutproc(void *v) { char *s; s = v; sleep(750); /* remove window from screen after 3/4 of a second */ sendp(deletechan, s); } /* * Button 6 - keyboard toggle - has been pressed. * Send event to keyboard, wait for button up, send that. * Note: there is no coordinate translation done here; this * is just about getting button 6 to the keyboard simulator. */ void keyboardhide(void) { send(wkeyboard->mc.c, mouse); do readmouse(mousectl); while(mouse->buttons & (1<<5)); send(wkeyboard->mc.c, mouse); } void mousethread(void*) { int sending, inside, scrolling, moving, band; Window *oin, *w, *winput; Image *i; Rectangle r; Point xy; Mouse tmp; enum { MReshape, MMouse, NALT }; static Alt alts[NALT+1]; threadsetname("mousethread"); sending = FALSE; scrolling = FALSE; moving = FALSE; alts[MReshape].c = mousectl->resizec; alts[MReshape].v = nil; alts[MReshape].op = CHANRCV; alts[MMouse].c = mousectl->c; alts[MMouse].v = &mousectl->Mouse; alts[MMouse].op = CHANRCV; alts[NALT].op = CHANEND; for(;;) switch(alt(alts)){ case MReshape: