this sucks!
This commit is contained in:
commit
f8064ab70e
12 changed files with 6402 additions and 0 deletions
343
dat.h
Normal file
343
dat.h
Normal file
|
|
@ -0,0 +1,343 @@
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Qdir, /* /dev for this window */
|
||||||
|
Qscreen,
|
||||||
|
Qsnarf,
|
||||||
|
Qwctl,
|
||||||
|
Qtap,
|
||||||
|
Qwsys, /* directory of window directories */
|
||||||
|
Qwsysdir, /* window directory, child of wsys */
|
||||||
|
|
||||||
|
Qcons,
|
||||||
|
Qconsctl,
|
||||||
|
Qcursor,
|
||||||
|
Qwdir,
|
||||||
|
Qwinid,
|
||||||
|
Qwinname,
|
||||||
|
Qlabel,
|
||||||
|
Qkbd,
|
||||||
|
Qmouse,
|
||||||
|
Qtext,
|
||||||
|
Qwindow,
|
||||||
|
|
||||||
|
QMAX,
|
||||||
|
Qglobal = Qcons, /* anything >= must have non nil window */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define STACK 8192
|
||||||
|
#define MAXSNARF 100*1024
|
||||||
|
|
||||||
|
typedef struct Consreadmesg Consreadmesg;
|
||||||
|
typedef struct Conswritemesg Conswritemesg;
|
||||||
|
typedef struct Kbdreadmesg Kbdreadmesg;
|
||||||
|
typedef struct Stringpair Stringpair;
|
||||||
|
typedef struct Dirtab Dirtab;
|
||||||
|
typedef struct Fid Fid;
|
||||||
|
typedef struct Filsys Filsys;
|
||||||
|
typedef struct Mouseinfo Mouseinfo;
|
||||||
|
typedef struct Mousereadmesg Mousereadmesg;
|
||||||
|
typedef struct Mousestate Mousestate;
|
||||||
|
typedef struct Ref Ref;
|
||||||
|
typedef struct Timer Timer;
|
||||||
|
typedef struct Wctlmesg Wctlmesg;
|
||||||
|
typedef struct Window Window;
|
||||||
|
typedef struct Xfid Xfid;
|
||||||
|
typedef struct Tapmesg Tapmesg;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Selborder = 4, /* border of selected window */
|
||||||
|
Unselborder = 1, /* border of unselected window */
|
||||||
|
Scrollwid = 12, /* width of scroll bar */
|
||||||
|
Scrollgap = 4, /* gap right of scroll bar */
|
||||||
|
BIG = 3, /* factor by which window dimension can exceed screen */
|
||||||
|
TRUE = 1,
|
||||||
|
FALSE = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QID(w,q) ((w<<8)|(q))
|
||||||
|
#define WIN(q) ((((ulong)(q).path)>>8) & 0xFFFFFF)
|
||||||
|
#define FILE(q) (((ulong)(q).path) & 0xFF)
|
||||||
|
|
||||||
|
enum /* control messages */
|
||||||
|
{
|
||||||
|
Wakeup,
|
||||||
|
Reshaped,
|
||||||
|
Topped,
|
||||||
|
Repaint,
|
||||||
|
Refresh,
|
||||||
|
Movemouse,
|
||||||
|
Rawon,
|
||||||
|
Rawoff,
|
||||||
|
Holdon,
|
||||||
|
Holdoff,
|
||||||
|
Truncate,
|
||||||
|
Deleted,
|
||||||
|
Exited,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Wctlmesg
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
Rectangle r;
|
||||||
|
void *p;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Conswritemesg
|
||||||
|
{
|
||||||
|
Channel *cw; /* chan(Stringpair) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Consreadmesg
|
||||||
|
{
|
||||||
|
Channel *c1; /* chan(tuple(char*, int) == Stringpair) */
|
||||||
|
Channel *c2; /* chan(tuple(char*, int) == Stringpair) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mousereadmesg
|
||||||
|
{
|
||||||
|
Channel *cm; /* chan(Mouse) */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Stringpair /* rune and nrune or byte and nbyte */
|
||||||
|
{
|
||||||
|
void *s;
|
||||||
|
int ns;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mousestate
|
||||||
|
{
|
||||||
|
Mouse;
|
||||||
|
ulong counter; /* serial no. of mouse event */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mouseinfo
|
||||||
|
{
|
||||||
|
Mousestate queue[16];
|
||||||
|
int ri; /* read index into queue */
|
||||||
|
int wi; /* write index */
|
||||||
|
ulong counter; /* serial no. of last mouse event we received */
|
||||||
|
ulong lastcounter; /* serial no. of last mouse event sent to client */
|
||||||
|
int lastb; /* last button state we received */
|
||||||
|
uchar qfull; /* filled the queue; no more recording until client comes back */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Window
|
||||||
|
{
|
||||||
|
Ref;
|
||||||
|
QLock;
|
||||||
|
Frame;
|
||||||
|
Image *i; /* window image, nil when deleted */
|
||||||
|
Mousectl mc;
|
||||||
|
Mouseinfo mouse;
|
||||||
|
Channel *ck; /* chan(char*) */
|
||||||
|
Channel *cctl; /* chan(Wctlmesg)[4] */
|
||||||
|
Channel *conswrite; /* chan(Conswritemesg) */
|
||||||
|
Channel *consread; /* chan(Consreadmesg) */
|
||||||
|
Channel *mouseread; /* chan(Mousereadmesg) */
|
||||||
|
Channel *wctlread; /* chan(Consreadmesg) */
|
||||||
|
Channel *kbdread; /* chan(Consreadmesg) */
|
||||||
|
Channel *complete; /* chan(Completion*) */
|
||||||
|
Channel *gone; /* chan(char*) */
|
||||||
|
uint nr; /* number of runes in window */
|
||||||
|
uint maxr; /* number of runes allocated in r */
|
||||||
|
Rune *r;
|
||||||
|
uint nraw;
|
||||||
|
Rune *raw;
|
||||||
|
uint org;
|
||||||
|
uint q0;
|
||||||
|
uint q1;
|
||||||
|
uint qh;
|
||||||
|
int id;
|
||||||
|
char name[32];
|
||||||
|
uint namecount;
|
||||||
|
Rectangle scrollr;
|
||||||
|
/*
|
||||||
|
* Rio once used originwindow, so screenr could be different from i->r.
|
||||||
|
* Now they're always the same but the code doesn't assume so.
|
||||||
|
*/
|
||||||
|
Rectangle screenr; /* screen coordinates of window */
|
||||||
|
int resized;
|
||||||
|
int wctlready;
|
||||||
|
Rectangle lastsr;
|
||||||
|
int topped;
|
||||||
|
int notefd;
|
||||||
|
uchar scrolling;
|
||||||
|
Cursor cursor;
|
||||||
|
Cursor *cursorp;
|
||||||
|
uchar holding;
|
||||||
|
uchar rawing;
|
||||||
|
uchar ctlopen;
|
||||||
|
uchar wctlopen;
|
||||||
|
uchar deleted;
|
||||||
|
uchar mouseopen;
|
||||||
|
uchar kbdopen;
|
||||||
|
uchar keyup;
|
||||||
|
uchar winnameread;
|
||||||
|
char *label;
|
||||||
|
char *dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
void winctl(void*);
|
||||||
|
void winshell(void*);
|
||||||
|
Window* wlookid(int);
|
||||||
|
Window* wmk(Image*, Mousectl*, Channel*, Channel*, int);
|
||||||
|
Window* wpointto(Point);
|
||||||
|
Window* wtop(Point);
|
||||||
|
void wtopme(Window*);
|
||||||
|
void wbottomme(Window*);
|
||||||
|
char* wcontents(Window*, int*);
|
||||||
|
int wclose(Window*);
|
||||||
|
uint wbacknl(Window*, uint, uint);
|
||||||
|
void wcurrent(Window*);
|
||||||
|
void wuncurrent(Window*);
|
||||||
|
void wcut(Window*);
|
||||||
|
void wpaste(Window*);
|
||||||
|
void wplumb(Window*);
|
||||||
|
void wlook(Window*);
|
||||||
|
void wscrdraw(Window*);
|
||||||
|
void wscroll(Window*, int);
|
||||||
|
void wsend(Window*);
|
||||||
|
void wsendctlmesg(Window*, int, Rectangle, void*);
|
||||||
|
void wsetcursor(Window*, int);
|
||||||
|
void wsetname(Window*);
|
||||||
|
void wsetorigin(Window*, uint, int);
|
||||||
|
void wsetpid(Window*, int, int);
|
||||||
|
void wshow(Window*, uint);
|
||||||
|
void wsnarf(Window*);
|
||||||
|
void wscrsleep(Window*, uint);
|
||||||
|
|
||||||
|
struct Dirtab
|
||||||
|
{
|
||||||
|
char *name;
|
||||||
|
uchar type;
|
||||||
|
uint qid;
|
||||||
|
uint perm;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Fid
|
||||||
|
{
|
||||||
|
int fid;
|
||||||
|
int busy;
|
||||||
|
int open;
|
||||||
|
int mode;
|
||||||
|
Qid qid;
|
||||||
|
Window *w;
|
||||||
|
Dirtab *dir;
|
||||||
|
Fid *next;
|
||||||
|
int nrpart;
|
||||||
|
uchar rpart[UTFmax];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Xfid
|
||||||
|
{
|
||||||
|
Ref;
|
||||||
|
Xfid *next;
|
||||||
|
Xfid *free;
|
||||||
|
Fcall;
|
||||||
|
Channel *c; /* chan(void(*)(Xfid*)) */
|
||||||
|
Fid *f;
|
||||||
|
uchar *buf;
|
||||||
|
Filsys *fs;
|
||||||
|
int flushtag; /* our tag, so flush can find us */
|
||||||
|
Channel *flushc; /* channel(int) to notify us we're being flushed */
|
||||||
|
};
|
||||||
|
|
||||||
|
Channel* xfidinit(void);
|
||||||
|
void xfidctl(void*);
|
||||||
|
void xfidflush(Xfid*);
|
||||||
|
void xfidattach(Xfid*);
|
||||||
|
void xfidopen(Xfid*);
|
||||||
|
void xfidclose(Xfid*);
|
||||||
|
void xfidread(Xfid*);
|
||||||
|
void xfidwrite(Xfid*);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Nhash = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Filsys
|
||||||
|
{
|
||||||
|
int cfd;
|
||||||
|
int sfd;
|
||||||
|
int pid;
|
||||||
|
char *user;
|
||||||
|
Channel *cxfidalloc; /* chan(Xfid*) */
|
||||||
|
Channel *csyncflush; /* chan(int) */
|
||||||
|
Fid *fids[Nhash];
|
||||||
|
};
|
||||||
|
|
||||||
|
Filsys* filsysinit(Channel*);
|
||||||
|
int filsysmount(Filsys*, int);
|
||||||
|
Xfid* filsysrespond(Filsys*, Xfid*, Fcall*, char*);
|
||||||
|
void filsyscancel(Xfid*);
|
||||||
|
|
||||||
|
void deletetimeoutproc(void*);
|
||||||
|
|
||||||
|
struct Timer
|
||||||
|
{
|
||||||
|
int dt;
|
||||||
|
int cancel;
|
||||||
|
Channel *c; /* chan(int) */
|
||||||
|
Timer *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
Font *font;
|
||||||
|
Mousectl *mousectl;
|
||||||
|
Mouse *mouse;
|
||||||
|
Display *display;
|
||||||
|
Image *view;
|
||||||
|
Screen *wscreen;
|
||||||
|
Cursor boxcursor;
|
||||||
|
Cursor crosscursor;
|
||||||
|
Cursor sightcursor;
|
||||||
|
Cursor whitearrow;
|
||||||
|
Cursor query;
|
||||||
|
Cursor *corners[9];
|
||||||
|
Cursor skull;
|
||||||
|
|
||||||
|
Image *background;
|
||||||
|
Image *cols[NCOL];
|
||||||
|
Image *titlecol;
|
||||||
|
Image *lighttitlecol;
|
||||||
|
Image *dholdcol;
|
||||||
|
Image *holdcol;
|
||||||
|
Image *lightholdcol;
|
||||||
|
Image *paleholdcol;
|
||||||
|
Image *paletextcol;
|
||||||
|
Image *sizecol;
|
||||||
|
int reverse; /* there are no pastel paints in the dungeons and dragons world -- rob pike */
|
||||||
|
|
||||||
|
Window **window;
|
||||||
|
Window *wkeyboard; /* window of simulated keyboard */
|
||||||
|
int nwindow;
|
||||||
|
int snarffd;
|
||||||
|
int gotscreen;
|
||||||
|
int servekbd;
|
||||||
|
|
||||||
|
Channel *opentap; /* open fromtap or totap */
|
||||||
|
Channel *closetap; /* close fromtap or totap */
|
||||||
|
Channel *fromtap; /* keyboard output from the tap program */
|
||||||
|
Channel *totap; /* our keyboard input to tap program */
|
||||||
|
|
||||||
|
Window *input;
|
||||||
|
QLock all; /* BUG */
|
||||||
|
Filsys *filsys;
|
||||||
|
Window *hidden[100];
|
||||||
|
int nhidden;
|
||||||
|
int nsnarf;
|
||||||
|
Rune* snarf;
|
||||||
|
int scrolling;
|
||||||
|
int maxtab;
|
||||||
|
Channel* winclosechan;
|
||||||
|
char *startdir;
|
||||||
|
int sweeping;
|
||||||
|
char srvpipe[];
|
||||||
|
char srvwctl[];
|
||||||
|
int errorshouldabort;
|
||||||
|
int menuing; /* menu action is pending; waiting for window to be indicated */
|
||||||
|
int snarfversion; /* updated each time it is written */
|
||||||
|
int messagesize; /* negotiated in 9P version setup */
|
||||||
|
int shiftdown;
|
||||||
|
int debug;
|
||||||
216
data.c
Normal file
216
data.c
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
#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 "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
Cursor crosscursor = {
|
||||||
|
{-7, -7},
|
||||||
|
{0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0,
|
||||||
|
0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0,
|
||||||
|
0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, },
|
||||||
|
{0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
|
||||||
|
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x7F, 0xFE,
|
||||||
|
0x7F, 0xFE, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
|
||||||
|
0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor boxcursor = {
|
||||||
|
{-7, -7},
|
||||||
|
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F,
|
||||||
|
0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, },
|
||||||
|
{0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE,
|
||||||
|
0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
|
||||||
|
0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E,
|
||||||
|
0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor sightcursor = {
|
||||||
|
{-7, -7},
|
||||||
|
{0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
|
||||||
|
0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
|
||||||
|
0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8, },
|
||||||
|
{0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
|
||||||
|
0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
|
||||||
|
0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
|
||||||
|
0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor whitearrow = {
|
||||||
|
{0, 0},
|
||||||
|
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
|
||||||
|
0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC,
|
||||||
|
0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
|
||||||
|
0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
|
||||||
|
{0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C,
|
||||||
|
0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C,
|
||||||
|
0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C,
|
||||||
|
0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor query = {
|
||||||
|
{-7,-7},
|
||||||
|
{0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe,
|
||||||
|
0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8,
|
||||||
|
0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0,
|
||||||
|
0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, },
|
||||||
|
{0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c,
|
||||||
|
0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0,
|
||||||
|
0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80,
|
||||||
|
0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor tl = {
|
||||||
|
{-4, -4},
|
||||||
|
{0xfe, 0x00, 0x82, 0x00, 0x8c, 0x00, 0x87, 0xff,
|
||||||
|
0xa0, 0x01, 0xb0, 0x01, 0xd0, 0x01, 0x11, 0xff,
|
||||||
|
0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
|
||||||
|
0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x1f, 0x00, },
|
||||||
|
{0x00, 0x00, 0x7c, 0x00, 0x70, 0x00, 0x78, 0x00,
|
||||||
|
0x5f, 0xfe, 0x4f, 0xfe, 0x0f, 0xfe, 0x0e, 0x00,
|
||||||
|
0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
|
||||||
|
0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor skull = {
|
||||||
|
{-7,-7},
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0xe7, 0xe7,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x3f, 0xfc, 0x1f, 0xf8,
|
||||||
|
0x0f, 0xf0, 0x3f, 0xfc, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xef, 0xf7, 0xc7, 0xe3, 0x00, 0x00, 0x00, 0x00,},
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03,
|
||||||
|
0xE7, 0xE7, 0x3F, 0xFC, 0x0F, 0xF0, 0x0D, 0xB0,
|
||||||
|
0x07, 0xE0, 0x06, 0x60, 0x37, 0xEC, 0xE4, 0x27,
|
||||||
|
0xC3, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor t = {
|
||||||
|
{-7, -8},
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x06, 0xc0,
|
||||||
|
0x1c, 0x70, 0x10, 0x10, 0x0c, 0x60, 0xfc, 0x7f,
|
||||||
|
0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
|
0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80, 0x03, 0x80,
|
||||||
|
0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor tr = {
|
||||||
|
{-11, -4},
|
||||||
|
{0x00, 0x7f, 0x00, 0x41, 0x00, 0x31, 0xff, 0xe1,
|
||||||
|
0x80, 0x05, 0x80, 0x0d, 0x80, 0x0b, 0xff, 0x88,
|
||||||
|
0x00, 0x88, 0x0, 0x88, 0x00, 0x88, 0x00, 0x88,
|
||||||
|
0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xf8, },
|
||||||
|
{0x00, 0x00, 0x00, 0x3e, 0x00, 0x0e, 0x00, 0x1e,
|
||||||
|
0x7f, 0xfa, 0x7f, 0xf2, 0x7f, 0xf0, 0x00, 0x70,
|
||||||
|
0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||||
|
0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor r = {
|
||||||
|
{-8, -7},
|
||||||
|
{0x07, 0xc0, 0x04, 0x40, 0x04, 0x40, 0x04, 0x58,
|
||||||
|
0x04, 0x68, 0x04, 0x6c, 0x04, 0x06, 0x04, 0x02,
|
||||||
|
0x04, 0x06, 0x04, 0x6c, 0x04, 0x68, 0x04, 0x58,
|
||||||
|
0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x07, 0xc0, },
|
||||||
|
{0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80,
|
||||||
|
0x03, 0x90, 0x03, 0x90, 0x03, 0xf8, 0x03, 0xfc,
|
||||||
|
0x03, 0xf8, 0x03, 0x90, 0x03, 0x90, 0x03, 0x80,
|
||||||
|
0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor br = {
|
||||||
|
{-11, -11},
|
||||||
|
{0x00, 0xf8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88,
|
||||||
|
0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88,
|
||||||
|
0xff, 0x88, 0x80, 0x0b, 0x80, 0x0d, 0x80, 0x05,
|
||||||
|
0xff, 0xe1, 0x00, 0x31, 0x00, 0x41, 0x00, 0x7f, },
|
||||||
|
{0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||||
|
0x0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70,
|
||||||
|
0x00, 0x70, 0x7f, 0xf0, 0x7f, 0xf2, 0x7f, 0xfa,
|
||||||
|
0x00, 0x1e, 0x00, 0x0e, 0x00, 0x3e, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor b = {
|
||||||
|
{-7, -7},
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xff, 0xff, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
|
||||||
|
0xfc, 0x7f, 0x0c, 0x60, 0x10, 0x10, 0x1c, 0x70,
|
||||||
|
0x06, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, },
|
||||||
|
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe,
|
||||||
|
0x03, 0x80, 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor bl = {
|
||||||
|
{-4, -11},
|
||||||
|
{0x1f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
|
||||||
|
0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00,
|
||||||
|
0x11, 0xff, 0xd0, 0x01, 0xb0, 0x01, 0xa0, 0x01,
|
||||||
|
0x87, 0xff, 0x8c, 0x00, 0x82, 0x00, 0xfe, 0x00, },
|
||||||
|
{0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
|
||||||
|
0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00,
|
||||||
|
0x0e, 0x00, 0x0f, 0xfe, 0x4f, 0xfe, 0x5f, 0xfe,
|
||||||
|
0x78, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x00, 0x0, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor l = {
|
||||||
|
{-7, -7},
|
||||||
|
{0x03, 0xe0, 0x02, 0x20, 0x02, 0x20, 0x1a, 0x20,
|
||||||
|
0x16, 0x20, 0x36, 0x20, 0x60, 0x20, 0x40, 0x20,
|
||||||
|
0x60, 0x20, 0x36, 0x20, 0x16, 0x20, 0x1a, 0x20,
|
||||||
|
0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x03, 0xe0, },
|
||||||
|
{0x00, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0,
|
||||||
|
0x09, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x3f, 0xc0,
|
||||||
|
0x1f, 0xc0, 0x09, 0xc0, 0x09, 0xc0, 0x01, 0xc0,
|
||||||
|
0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, }
|
||||||
|
};
|
||||||
|
|
||||||
|
Cursor *corners[9] = {
|
||||||
|
&tl, &t, &tr,
|
||||||
|
&l, nil, &r,
|
||||||
|
&bl, &b, &br,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
iconinit(void)
|
||||||
|
{
|
||||||
|
background = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x777777FF);
|
||||||
|
|
||||||
|
/* greys are multiples of 0x11111100+0xFF, 14* being palest */
|
||||||
|
cols[BACK] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xFFFFFFFF^reverse);
|
||||||
|
cols[BORD] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x999999FF^reverse);
|
||||||
|
cols[TEXT] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x000000FF^reverse);
|
||||||
|
cols[HTEXT] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x000000FF);
|
||||||
|
if(!reverse) {
|
||||||
|
cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
|
||||||
|
titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreygreen);
|
||||||
|
lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreygreen);
|
||||||
|
} else {
|
||||||
|
cols[HIGH] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPurpleblue);
|
||||||
|
titlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPurpleblue);
|
||||||
|
lighttitlecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x222222FF);
|
||||||
|
}
|
||||||
|
dholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DMedblue);
|
||||||
|
lightholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DGreyblue);
|
||||||
|
paleholdcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DPalegreyblue);
|
||||||
|
paletextcol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x666666FF^reverse);
|
||||||
|
sizecol = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DRed);
|
||||||
|
|
||||||
|
if(reverse == 0)
|
||||||
|
holdcol = dholdcol;
|
||||||
|
else
|
||||||
|
holdcol = paleholdcol;
|
||||||
|
}
|
||||||
36
fns.h
Normal file
36
fns.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
int whide(Window*);
|
||||||
|
int wunhide(Window*);
|
||||||
|
void freescrtemps(void);
|
||||||
|
int parsewctl(char**, Rectangle, Rectangle*, int*, int*, int*, int*, char**, char*, char*);
|
||||||
|
int writewctl(Xfid*, char*);
|
||||||
|
Window *new(Image*, int, int, int, char*, char*, char**);
|
||||||
|
void riosetcursor(Cursor*);
|
||||||
|
int min(int, int);
|
||||||
|
int max(int, int);
|
||||||
|
Rune* strrune(Rune*, Rune);
|
||||||
|
int isalnum(Rune);
|
||||||
|
int isspace(Rune);
|
||||||
|
void timerstop(Timer*);
|
||||||
|
void timercancel(Timer*);
|
||||||
|
Timer* timerstart(int);
|
||||||
|
void error(char*);
|
||||||
|
void killprocs(void);
|
||||||
|
int shutdown(void*, char*);
|
||||||
|
void iconinit(void);
|
||||||
|
void *erealloc(void*, uint);
|
||||||
|
void *emalloc(uint);
|
||||||
|
char *estrdup(char*);
|
||||||
|
void button3menu(void);
|
||||||
|
void button2menu(Window*);
|
||||||
|
void cvttorunes(char*, int, Rune*, int*, int*, int*);
|
||||||
|
/* was (byte*,int) runetobyte(Rune*, int); */
|
||||||
|
char* runetobyte(Rune*, int, int*);
|
||||||
|
void putsnarf(void);
|
||||||
|
void getsnarf(void);
|
||||||
|
void timerinit(void);
|
||||||
|
int goodrect(Rectangle);
|
||||||
|
int inborder(Rectangle, Point);
|
||||||
|
|
||||||
|
#define runemalloc(n) malloc((n)*sizeof(Rune))
|
||||||
|
#define runerealloc(a, n) realloc(a, (n)*sizeof(Rune))
|
||||||
|
#define runemove(a, b, n) memmove(a, b, (n)*sizeof(Rune))
|
||||||
701
fsys.c
Normal file
701
fsys.c
Normal file
|
|
@ -0,0 +1,701 @@
|
||||||
|
#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 "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
char Eperm[] = "permission denied";
|
||||||
|
char Eexist[] = "file does not exist";
|
||||||
|
char Enotdir[] = "not a directory";
|
||||||
|
char Ebadfcall[] = "bad fcall type";
|
||||||
|
char Eoffset[] = "illegal offset";
|
||||||
|
char Enomem[] = "out of memory";
|
||||||
|
|
||||||
|
int messagesize = 8192+IOHDRSZ; /* good start */
|
||||||
|
|
||||||
|
Dirtab dirtab[]=
|
||||||
|
{
|
||||||
|
{ ".", QTDIR, Qdir, 0500|DMDIR },
|
||||||
|
{ "screen", QTFILE, Qscreen, 0400 },
|
||||||
|
{ "snarf", QTFILE, Qsnarf, 0600 },
|
||||||
|
{ "wctl", QTFILE, Qwctl, 0600 },
|
||||||
|
{ "kbdtap", QTFILE, Qtap, 0660 },
|
||||||
|
{ "wsys", QTDIR, Qwsys, 0500|DMDIR },
|
||||||
|
|
||||||
|
{ "cons", QTFILE, Qcons, 0600 },
|
||||||
|
{ "cursor", QTFILE, Qcursor, 0600 },
|
||||||
|
{ "consctl", QTFILE, Qconsctl, 0200 },
|
||||||
|
{ "winid", QTFILE, Qwinid, 0400 },
|
||||||
|
{ "winname", QTFILE, Qwinname, 0400 },
|
||||||
|
{ "label", QTFILE, Qlabel, 0600 },
|
||||||
|
{ "kbd", QTFILE, Qkbd, 0600 },
|
||||||
|
{ "mouse", QTFILE, Qmouse, 0600 },
|
||||||
|
{ "text", QTFILE, Qtext, 0600 },
|
||||||
|
{ "wdir", QTFILE, Qwdir, 0600 },
|
||||||
|
{ "window", QTFILE, Qwindow, 0400 },
|
||||||
|
{ nil, }
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint getclock(void);
|
||||||
|
static void filsysproc(void*);
|
||||||
|
static Fid* newfid(Filsys*, int);
|
||||||
|
static int dostat(Filsys*, int, Dirtab*, uchar*, int, uint);
|
||||||
|
|
||||||
|
int clockfd;
|
||||||
|
int firstmessage = 1;
|
||||||
|
|
||||||
|
char srvpipe[64];
|
||||||
|
char srvwctl[64];
|
||||||
|
|
||||||
|
static Xfid* filsysflush(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysversion(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysauth(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysattach(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsyswalk(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysopen(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsyscreate(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysread(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsyswrite(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysclunk(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysremove(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsysstat(Filsys*, Xfid*, Fid*);
|
||||||
|
static Xfid* filsyswstat(Filsys*, Xfid*, Fid*);
|
||||||
|
|
||||||
|
Xfid* (*fcall[Tmax])(Filsys*, Xfid*, Fid*) =
|
||||||
|
{
|
||||||
|
[Tflush] = filsysflush,
|
||||||
|
[Tversion] = filsysversion,
|
||||||
|
[Tauth] = filsysauth,
|
||||||
|
[Tattach] = filsysattach,
|
||||||
|
[Twalk] = filsyswalk,
|
||||||
|
[Topen] = filsysopen,
|
||||||
|
[Tcreate] = filsyscreate,
|
||||||
|
[Tread] = filsysread,
|
||||||
|
[Twrite] = filsyswrite,
|
||||||
|
[Tclunk] = filsysclunk,
|
||||||
|
[Tremove]= filsysremove,
|
||||||
|
[Tstat] = filsysstat,
|
||||||
|
[Twstat] = filsyswstat,
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
post(char *name, char *envname, int srvfd)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600);
|
||||||
|
if(fd < 0)
|
||||||
|
error(name);
|
||||||
|
snprint(buf, sizeof(buf), "%d", srvfd);
|
||||||
|
if(write(fd, buf, strlen(buf)) != strlen(buf))
|
||||||
|
error("srv write");
|
||||||
|
putenv(envname, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build pipe with OCEXEC set on second fd.
|
||||||
|
* Can't put it on both because we want to post one in /srv.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cexecpipe(int *p0, int *p1)
|
||||||
|
{
|
||||||
|
/* pipe the hard way to get close on exec */
|
||||||
|
if(bind("#|", "/mnt/temp", MREPL) == -1)
|
||||||
|
return -1;
|
||||||
|
*p0 = open("/mnt/temp/data", ORDWR);
|
||||||
|
*p1 = open("/mnt/temp/data1", ORDWR|OCEXEC);
|
||||||
|
unmount(nil, "/mnt/temp");
|
||||||
|
if(*p0<0 || *p1<0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Filsys*
|
||||||
|
filsysinit(Channel *cxfidalloc)
|
||||||
|
{
|
||||||
|
Filsys *fs;
|
||||||
|
|
||||||
|
fs = emalloc(sizeof(Filsys));
|
||||||
|
if(cexecpipe(&fs->cfd, &fs->sfd) < 0)
|
||||||
|
goto Rescue;
|
||||||
|
fmtinstall('F', fcallfmt);
|
||||||
|
clockfd = open("/dev/time", OREAD|OCEXEC);
|
||||||
|
fs->user = getuser();
|
||||||
|
fs->csyncflush = chancreate(sizeof(int), 0);
|
||||||
|
if(fs->csyncflush == nil)
|
||||||
|
error("chancreate syncflush");
|
||||||
|
fs->cxfidalloc = cxfidalloc;
|
||||||
|
|
||||||
|
proccreate(filsysproc, fs, 10000);
|
||||||
|
snprint(srvpipe, sizeof(srvpipe), "/srv/rio.%s.%lud", fs->user, (ulong)getpid());
|
||||||
|
post(srvpipe, "wsys", fs->cfd);
|
||||||
|
|
||||||
|
return fs;
|
||||||
|
|
||||||
|
Rescue:
|
||||||
|
free(fs);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
filsysproc(void *arg)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
Xfid *x;
|
||||||
|
Fid *f;
|
||||||
|
Fcall t;
|
||||||
|
uchar *buf;
|
||||||
|
Filsys *fs;
|
||||||
|
|
||||||
|
threadsetname("FILSYSPROC");
|
||||||
|
fs = arg;
|
||||||
|
fs->pid = getpid();
|
||||||
|
x = nil;
|
||||||
|
for(;;){
|
||||||
|
buf = malloc(messagesize+UTFmax); /* UTFmax for appending partial rune in xfidwrite */
|
||||||
|
if(buf == nil)
|
||||||
|
error(Enomem);
|
||||||
|
n = read9pmsg(fs->sfd, buf, messagesize);
|
||||||
|
if(n <= 0){
|
||||||
|
yield(); /* if threadexitsall'ing, will not return */
|
||||||
|
fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n);
|
||||||
|
errorshouldabort = 0;
|
||||||
|
error("eof or i/o error on server channel");
|
||||||
|
}
|
||||||
|
if(x == nil){
|
||||||
|
send(fs->cxfidalloc, nil);
|
||||||
|
recv(fs->cxfidalloc, &x);
|
||||||
|
x->fs = fs;
|
||||||
|
}
|
||||||
|
x->buf = buf;
|
||||||
|
if(convM2S(buf, n, x) != n)
|
||||||
|
error("convert error in convM2S");
|
||||||
|
if(debug)
|
||||||
|
fprint(2, "rio:<-%F\n", &x->Fcall);
|
||||||
|
if(fcall[x->type] == nil)
|
||||||
|
x = filsysrespond(fs, x, &t, Ebadfcall);
|
||||||
|
else{
|
||||||
|
if(x->type==Tversion || x->type==Tauth)
|
||||||
|
f = nil;
|
||||||
|
else
|
||||||
|
f = newfid(fs, x->fid);
|
||||||
|
x->f = f;
|
||||||
|
x = (*fcall[x->type])(fs, x, f);
|
||||||
|
}
|
||||||
|
firstmessage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called only from a different FD group
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
filsysmount(Filsys *fs, int id)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
close(fs->sfd); /* close server end so mount won't hang if exiting */
|
||||||
|
snprint(buf, sizeof buf, "%d", id);
|
||||||
|
if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) == -1){
|
||||||
|
fprint(2, "mount failed: %r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(bind("/mnt/wsys", "/dev", MBEFORE) == -1){
|
||||||
|
fprint(2, "bind failed: %r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Xfid*
|
||||||
|
filsysrespond(Filsys *fs, Xfid *x, Fcall *t, char *err)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(err){
|
||||||
|
t->type = Rerror;
|
||||||
|
t->ename = err;
|
||||||
|
}else
|
||||||
|
t->type = x->type+1;
|
||||||
|
t->fid = x->fid;
|
||||||
|
t->tag = x->tag;
|
||||||
|
if(x->buf == nil)
|
||||||
|
error("no buffer in respond");
|
||||||
|
n = convS2M(t, x->buf, messagesize);
|
||||||
|
if(n <= 0)
|
||||||
|
error("convert error in convS2M");
|
||||||
|
if(write(fs->sfd, x->buf, n) != n)
|
||||||
|
error("write error in respond");
|
||||||
|
if(debug)
|
||||||
|
fprint(2, "rio:->%F\n", t);
|
||||||
|
free(x->buf);
|
||||||
|
x->buf = nil;
|
||||||
|
x->flushtag = -1;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
filsyscancel(Xfid *x)
|
||||||
|
{
|
||||||
|
if(x->buf){
|
||||||
|
free(x->buf);
|
||||||
|
x->buf = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysversion(Filsys *fs, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
if(!firstmessage)
|
||||||
|
return filsysrespond(x->fs, x, &t, "version request not first message");
|
||||||
|
if(x->msize < 256)
|
||||||
|
return filsysrespond(x->fs, x, &t, "version: message size too small");
|
||||||
|
messagesize = x->msize;
|
||||||
|
t.msize = messagesize;
|
||||||
|
t.version = "9P2000";
|
||||||
|
if(strncmp(x->version, "9P", 2) != 0)
|
||||||
|
t.version = "unknown";
|
||||||
|
return filsysrespond(fs, x, &t, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysauth(Filsys *fs, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
return filsysrespond(fs, x, &t, "rio: authentication not required");
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysflush(Filsys *fs, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
sendp(x->c, xfidflush);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flushes need to be replied in order. xfidflush() will
|
||||||
|
* awaken us when the flush has been queued.
|
||||||
|
*/
|
||||||
|
recv(fs->csyncflush, nil);
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysattach(Filsys *, Xfid *x, Fid *f)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
if(strcmp(x->uname, x->fs->user) != 0)
|
||||||
|
return filsysrespond(x->fs, x, &t, Eperm);
|
||||||
|
f->busy = TRUE;
|
||||||
|
f->open = FALSE;
|
||||||
|
f->qid.path = Qdir;
|
||||||
|
f->qid.type = QTDIR;
|
||||||
|
f->qid.vers = 0;
|
||||||
|
f->dir = dirtab;
|
||||||
|
f->nrpart = 0;
|
||||||
|
sendp(x->c, xfidattach);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
numeric(char *s)
|
||||||
|
{
|
||||||
|
for(; *s!='\0'; s++)
|
||||||
|
if(*s<'0' || '9'<*s)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
skipdir(char *name)
|
||||||
|
{
|
||||||
|
/* don't serve these if it's provided in the environment */
|
||||||
|
if(snarffd>=0 && strcmp(name, "snarf")==0)
|
||||||
|
return 1;
|
||||||
|
if(gotscreen && strcmp(name, "screen")==0)
|
||||||
|
return 1;
|
||||||
|
if(!servekbd && strcmp(name, "kbd")==0)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsyswalk(Filsys *fs, Xfid *x, Fid *f)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
Fid *nf;
|
||||||
|
int i, id;
|
||||||
|
uchar type;
|
||||||
|
ulong path;
|
||||||
|
Dirtab *d, *dir;
|
||||||
|
Window *w;
|
||||||
|
char *err;
|
||||||
|
Qid qid;
|
||||||
|
|
||||||
|
if(f->open)
|
||||||
|
return filsysrespond(fs, x, &t, "walk of open file");
|
||||||
|
nf = nil;
|
||||||
|
if(x->fid != x->newfid){
|
||||||
|
/* BUG: check exists */
|
||||||
|
nf = newfid(fs, x->newfid);
|
||||||
|
if(nf->busy)
|
||||||
|
return filsysrespond(fs, x, &t, "clone to busy fid");
|
||||||
|
nf->busy = TRUE;
|
||||||
|
nf->open = FALSE;
|
||||||
|
nf->dir = f->dir;
|
||||||
|
nf->qid = f->qid;
|
||||||
|
nf->w = f->w;
|
||||||
|
if(f->w != nil)
|
||||||
|
incref(f->w);
|
||||||
|
nf->nrpart = 0; /* not open, so must be zero */
|
||||||
|
f = nf; /* walk f */
|
||||||
|
}
|
||||||
|
|
||||||
|
t.nwqid = 0;
|
||||||
|
err = nil;
|
||||||
|
|
||||||
|
/* update f->qid, f->dir only if walk completes */
|
||||||
|
qid = f->qid;
|
||||||
|
dir = f->dir;
|
||||||
|
|
||||||
|
if(x->nwname > 0){
|
||||||
|
for(i=0; i<x->nwname; i++){
|
||||||
|
if((qid.type & QTDIR) == 0){
|
||||||
|
err = Enotdir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strcmp(x->wname[i], "..") == 0){
|
||||||
|
type = QTDIR;
|
||||||
|
path = Qdir;
|
||||||
|
dir = dirtab;
|
||||||
|
if(FILE(qid) == Qwsysdir)
|
||||||
|
path = Qwsys;
|
||||||
|
id = 0;
|
||||||
|
Accept:
|
||||||
|
if(i == MAXWELEM){
|
||||||
|
err = "name too long";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
qid.type = type;
|
||||||
|
qid.vers = 0;
|
||||||
|
qid.path = QID(id, path);
|
||||||
|
t.wqid[t.nwqid++] = qid;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(qid.path == Qwsys){
|
||||||
|
/* is it a numeric name? */
|
||||||
|
if(!numeric(x->wname[i]))
|
||||||
|
break;
|
||||||
|
/* yes: it's a directory */
|
||||||
|
id = atoi(x->wname[i]);
|
||||||
|
qlock(&all);
|
||||||
|
w = wlookid(id);
|
||||||
|
if(w == nil){
|
||||||
|
qunlock(&all);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path = Qwsysdir;
|
||||||
|
type = QTDIR;
|
||||||
|
qunlock(&all);
|
||||||
|
incref(w);
|
||||||
|
if(f->w)
|
||||||
|
sendp(winclosechan, f->w);
|
||||||
|
f->w = w;
|
||||||
|
dir = dirtab;
|
||||||
|
goto Accept;
|
||||||
|
}
|
||||||
|
if(skipdir(x->wname[i]))
|
||||||
|
break;
|
||||||
|
id = WIN(f->qid);
|
||||||
|
d = dirtab;
|
||||||
|
d++; /* skip '.' */
|
||||||
|
for(; d->name; d++)
|
||||||
|
if(strcmp(x->wname[i], d->name) == 0){
|
||||||
|
if(f->w == nil && d->qid >= Qglobal)
|
||||||
|
break;
|
||||||
|
path = d->qid;
|
||||||
|
type = d->type;
|
||||||
|
dir = d;
|
||||||
|
goto Accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
break; /* file not found */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i==0 && err==nil)
|
||||||
|
err = Eexist;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(err!=nil || t.nwqid<x->nwname){
|
||||||
|
if(nf){
|
||||||
|
if(nf->w)
|
||||||
|
sendp(winclosechan, nf->w);
|
||||||
|
nf->open = FALSE;
|
||||||
|
nf->busy = FALSE;
|
||||||
|
}
|
||||||
|
}else if(t.nwqid == x->nwname){
|
||||||
|
f->dir = dir;
|
||||||
|
f->qid = qid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filsysrespond(fs, x, &t, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysopen(Filsys *fs, Xfid *x, Fid *f)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
int m;
|
||||||
|
|
||||||
|
/* can't truncate anything but Qtext, so just disregard */
|
||||||
|
if(FILE(f->qid) != Qtext)
|
||||||
|
x->mode &= ~OTRUNC;
|
||||||
|
x->mode &= ~OCEXEC;
|
||||||
|
/* can't execute or remove anything */
|
||||||
|
if(x->mode==OEXEC || (x->mode&ORCLOSE))
|
||||||
|
goto Deny;
|
||||||
|
switch(x->mode & ~OTRUNC){
|
||||||
|
default:
|
||||||
|
goto Deny;
|
||||||
|
case OREAD:
|
||||||
|
m = 0400;
|
||||||
|
break;
|
||||||
|
case OWRITE:
|
||||||
|
m = 0200;
|
||||||
|
break;
|
||||||
|
case ORDWR:
|
||||||
|
m = 0600;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
|
||||||
|
goto Deny;
|
||||||
|
|
||||||
|
sendp(x->c, xfidopen);
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
Deny:
|
||||||
|
return filsysrespond(fs, x, &t, Eperm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsyscreate(Filsys *fs, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
return filsysrespond(fs, x, &t, Eperm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
idcmp(void *a, void *b)
|
||||||
|
{
|
||||||
|
return *(int*)a - *(int*)b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysread(Filsys *fs, Xfid *x, Fid *f)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
uchar *b;
|
||||||
|
int i, n, o, e, len, j, k, *ids;
|
||||||
|
Dirtab *d, dt;
|
||||||
|
uint clock;
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
if((f->qid.type & QTDIR) == 0){
|
||||||
|
sendp(x->c, xfidread);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
o = x->offset;
|
||||||
|
e = x->offset+x->count;
|
||||||
|
clock = getclock();
|
||||||
|
b = malloc(messagesize-IOHDRSZ); /* avoid memset of emalloc */
|
||||||
|
if(b == nil)
|
||||||
|
return filsysrespond(fs, x, &t, Enomem);
|
||||||
|
n = 0;
|
||||||
|
switch(FILE(f->qid)){
|
||||||
|
case Qdir:
|
||||||
|
case Qwsysdir:
|
||||||
|
d = dirtab;
|
||||||
|
d++; /* first entry is '.' */
|
||||||
|
for(i=0; d->name!=nil && i<e; d++){
|
||||||
|
if(skipdir(d->name))
|
||||||
|
continue;
|
||||||
|
if(f->w == nil && d->qid >= Qglobal)
|
||||||
|
continue;
|
||||||
|
len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock);
|
||||||
|
if(len <= BIT16SZ)
|
||||||
|
break;
|
||||||
|
if(i >= o)
|
||||||
|
n += len;
|
||||||
|
i += len;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Qwsys:
|
||||||
|
qlock(&all);
|
||||||
|
ids = emalloc(nwindow*sizeof(int));
|
||||||
|
for(j=0; j<nwindow; j++)
|
||||||
|
ids[j] = window[j]->id;
|
||||||
|
qunlock(&all);
|
||||||
|
qsort(ids, nwindow, sizeof ids[0], idcmp);
|
||||||
|
dt.name = buf;
|
||||||
|
for(i=0, j=0; j<nwindow && i<e; i+=len){
|
||||||
|
k = ids[j];
|
||||||
|
sprint(dt.name, "%d", k);
|
||||||
|
dt.qid = QID(k, Qdir);
|
||||||
|
dt.type = QTDIR;
|
||||||
|
dt.perm = DMDIR|0700;
|
||||||
|
len = dostat(fs, k, &dt, b+n, x->count-n, clock);
|
||||||
|
if(len == 0)
|
||||||
|
break;
|
||||||
|
if(i >= o)
|
||||||
|
n += len;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
free(ids);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t.data = (char*)b;
|
||||||
|
t.count = n;
|
||||||
|
filsysrespond(fs, x, &t, nil);
|
||||||
|
free(b);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsyswrite(Filsys*, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
sendp(x->c, xfidwrite);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysclunk(Filsys *fs, Xfid *x, Fid *f)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
if(f->open){
|
||||||
|
f->busy = FALSE;
|
||||||
|
f->open = FALSE;
|
||||||
|
sendp(x->c, xfidclose);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if(f->w)
|
||||||
|
sendp(winclosechan, f->w);
|
||||||
|
f->busy = FALSE;
|
||||||
|
f->open = FALSE;
|
||||||
|
return filsysrespond(fs, x, &t, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysremove(Filsys *fs, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
return filsysrespond(fs, x, &t, Eperm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsysstat(Filsys *fs, Xfid *x, Fid *f)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
t.stat = emalloc(messagesize-IOHDRSZ);
|
||||||
|
t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
|
||||||
|
x = filsysrespond(fs, x, &t, nil);
|
||||||
|
free(t.stat);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Xfid*
|
||||||
|
filsyswstat(Filsys *fs, Xfid *x, Fid*)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
|
||||||
|
return filsysrespond(fs, x, &t, Eperm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Fid*
|
||||||
|
newfid(Filsys *fs, int fid)
|
||||||
|
{
|
||||||
|
Fid *f, *ff, **fh;
|
||||||
|
|
||||||
|
ff = nil;
|
||||||
|
fh = &fs->fids[fid&(Nhash-1)];
|
||||||
|
for(f=*fh; f; f=f->next)
|
||||||
|
if(f->fid == fid)
|
||||||
|
return f;
|
||||||
|
else if(ff==nil && f->busy==FALSE)
|
||||||
|
ff = f;
|
||||||
|
if(ff){
|
||||||
|
ff->fid = fid;
|
||||||
|
return ff;
|
||||||
|
}
|
||||||
|
f = emalloc(sizeof *f);
|
||||||
|
f->fid = fid;
|
||||||
|
f->next = *fh;
|
||||||
|
*fh = f;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
uint
|
||||||
|
getclock(void)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
|
||||||
|
seek(clockfd, 0, 0);
|
||||||
|
read(clockfd, buf, sizeof buf);
|
||||||
|
return atoi(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
dostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
|
||||||
|
{
|
||||||
|
Dir d;
|
||||||
|
|
||||||
|
d.qid.path = QID(id, dir->qid);
|
||||||
|
if(dir->qid == Qsnarf)
|
||||||
|
d.qid.vers = snarfversion;
|
||||||
|
else
|
||||||
|
d.qid.vers = 0;
|
||||||
|
d.qid.type = dir->type;
|
||||||
|
d.mode = dir->perm;
|
||||||
|
d.length = 0; /* would be nice to do better */
|
||||||
|
d.name = dir->name;
|
||||||
|
d.uid = fs->user;
|
||||||
|
d.gid = fs->user;
|
||||||
|
d.muid = fs->user;
|
||||||
|
d.atime = clock;
|
||||||
|
d.mtime = clock;
|
||||||
|
return convD2M(&d, buf, nbuf);
|
||||||
|
}
|
||||||
25
mkfile
Normal file
25
mkfile
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
</$objtype/mkfile
|
||||||
|
BIN=$home/bin/$objtype
|
||||||
|
|
||||||
|
TARG=rio
|
||||||
|
OFILES=\
|
||||||
|
rio.$O\
|
||||||
|
data.$O\
|
||||||
|
fsys.$O\
|
||||||
|
scrl.$O\
|
||||||
|
time.$O\
|
||||||
|
util.$O\
|
||||||
|
wctl.$O\
|
||||||
|
wind.$O\
|
||||||
|
xfid.$O\
|
||||||
|
|
||||||
|
HFILES=dat.h\
|
||||||
|
fns.h\
|
||||||
|
|
||||||
|
</sys/src/cmd/mkone
|
||||||
|
|
||||||
|
$O.out: /$objtype/lib/libdraw.a /$objtype/lib/libframe.a \
|
||||||
|
/$objtype/lib/libthread.a /$objtype/lib/libplumb.a /$objtype/lib/libc.a
|
||||||
|
syms:V:
|
||||||
|
$CC -a $CFLAGS rio.c > syms
|
||||||
|
$CC -aa $CFLAGS *.c >>syms
|
||||||
182
scrl.c
Normal file
182
scrl.c
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
#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 "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static Image *scrtmp;
|
||||||
|
|
||||||
|
static
|
||||||
|
Image*
|
||||||
|
scrtemps(void)
|
||||||
|
{
|
||||||
|
int h;
|
||||||
|
|
||||||
|
if(scrtmp == nil){
|
||||||
|
h = BIG*Dy(screen->r);
|
||||||
|
scrtmp = allocimage(display, Rect(0, 0, 32, h), screen->chan, 0, DNofill);
|
||||||
|
}
|
||||||
|
return scrtmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freescrtemps(void)
|
||||||
|
{
|
||||||
|
if(scrtmp){
|
||||||
|
freeimage(scrtmp);
|
||||||
|
scrtmp = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
Rectangle
|
||||||
|
scrpos(Rectangle r, uint p0, uint p1, uint tot)
|
||||||
|
{
|
||||||
|
Rectangle q;
|
||||||
|
int h;
|
||||||
|
|
||||||
|
q = r;
|
||||||
|
h = q.max.y-q.min.y;
|
||||||
|
if(tot == 0)
|
||||||
|
return q;
|
||||||
|
if(tot > 1024*1024){
|
||||||
|
tot>>=10;
|
||||||
|
p0>>=10;
|
||||||
|
p1>>=10;
|
||||||
|
}
|
||||||
|
if(p0 > 0)
|
||||||
|
q.min.y += h*p0/tot;
|
||||||
|
if(p1 < tot)
|
||||||
|
q.max.y -= h*(tot-p1)/tot;
|
||||||
|
if(q.max.y < q.min.y+2){
|
||||||
|
if(q.min.y+2 <= r.max.y)
|
||||||
|
q.max.y = q.min.y+2;
|
||||||
|
else
|
||||||
|
q.min.y = q.max.y-2;
|
||||||
|
}
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wscrdraw(Window *w)
|
||||||
|
{
|
||||||
|
Rectangle r, r1, r2;
|
||||||
|
Image *b;
|
||||||
|
|
||||||
|
b = scrtemps();
|
||||||
|
if(b == nil || w->i == nil)
|
||||||
|
return;
|
||||||
|
r = w->scrollr;
|
||||||
|
r.min.x++;
|
||||||
|
r1 = r;
|
||||||
|
|
||||||
|
draw(b, r, display->black, nil, ZP);
|
||||||
|
r2 = scrpos(r1, w->org, w->org+w->nchars, w->nr);
|
||||||
|
if(!eqrect(r2, w->lastsr)){
|
||||||
|
w->lastsr = r2;
|
||||||
|
/* move r1, r2 to (0,0) to avoid clipping */
|
||||||
|
r2 = rectsubpt(r2, r1.min);
|
||||||
|
r1 = rectsubpt(r1, r1.min);
|
||||||
|
r2 = insetrect(r2, 1);
|
||||||
|
draw(b, r1, display->black, nil, ZP);
|
||||||
|
draw(b, insetrect(r1,1), w->cols[BORD], nil, ZP);
|
||||||
|
draw(b, r2, w->cols[BACK], nil, ZP);
|
||||||
|
draw(w->i, r, b, nil, Pt(0, r1.min.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wscrsleep(Window *w, uint dt)
|
||||||
|
{
|
||||||
|
Timer *timer;
|
||||||
|
int y, b;
|
||||||
|
static Alt alts[3];
|
||||||
|
|
||||||
|
if(display->bufp > display->buf)
|
||||||
|
flushimage(display, 1);
|
||||||
|
timer = timerstart(dt);
|
||||||
|
y = w->mc.xy.y;
|
||||||
|
b = w->mc.buttons;
|
||||||
|
alts[0].c = timer->c;
|
||||||
|
alts[0].v = nil;
|
||||||
|
alts[0].op = CHANRCV;
|
||||||
|
alts[1].c = w->mc.c;
|
||||||
|
alts[1].v = &w->mc.Mouse;
|
||||||
|
alts[1].op = CHANRCV;
|
||||||
|
alts[2].op = CHANEND;
|
||||||
|
for(;;)
|
||||||
|
switch(alt(alts)){
|
||||||
|
case 0:
|
||||||
|
timerstop(timer);
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
if(abs(w->mc.xy.y-y)>2 || w->mc.buttons!=b){
|
||||||
|
timercancel(timer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wscroll(Window *w, int but)
|
||||||
|
{
|
||||||
|
uint p0, oldp0;
|
||||||
|
Rectangle s;
|
||||||
|
int y, my, h, first;
|
||||||
|
|
||||||
|
s = insetrect(w->scrollr, 1);
|
||||||
|
h = s.max.y-s.min.y;
|
||||||
|
oldp0 = ~0;
|
||||||
|
first = TRUE;
|
||||||
|
do{
|
||||||
|
my = w->mc.xy.y;
|
||||||
|
if(my < s.min.y)
|
||||||
|
my = s.min.y;
|
||||||
|
if(my >= s.max.y)
|
||||||
|
my = s.max.y;
|
||||||
|
if(but == 2){
|
||||||
|
y = my;
|
||||||
|
if(y > s.max.y-2)
|
||||||
|
y = s.max.y-2;
|
||||||
|
if(w->nr > 1024*1024)
|
||||||
|
p0 = ((w->nr>>10)*(y-s.min.y)/h)<<10;
|
||||||
|
else
|
||||||
|
p0 = w->nr*(y-s.min.y)/h;
|
||||||
|
if(oldp0 != p0)
|
||||||
|
wsetorigin(w, p0, FALSE);
|
||||||
|
oldp0 = p0;
|
||||||
|
readmouse(&w->mc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(but == 1 || but == 4){
|
||||||
|
y = max(1, (my-s.min.y)/w->font->height);
|
||||||
|
p0 = wbacknl(w, w->org, y);
|
||||||
|
}else{
|
||||||
|
y = max(my, s.min.y+w->font->height);
|
||||||
|
p0 = w->org+frcharofpt(w, Pt(s.max.x, y));
|
||||||
|
}
|
||||||
|
if(oldp0 != p0)
|
||||||
|
wsetorigin(w, p0, TRUE);
|
||||||
|
oldp0 = p0;
|
||||||
|
/* debounce */
|
||||||
|
if(first){
|
||||||
|
if(display->bufp > display->buf)
|
||||||
|
flushimage(display, 1);
|
||||||
|
if(but > 3)
|
||||||
|
return;
|
||||||
|
sleep(200);
|
||||||
|
nbrecv(w->mc.c, &w->mc.Mouse);
|
||||||
|
first = FALSE;
|
||||||
|
}
|
||||||
|
wscrsleep(w, 100);
|
||||||
|
}while(w->mc.buttons & (1<<(but-1)));
|
||||||
|
while(w->mc.buttons)
|
||||||
|
readmouse(&w->mc);
|
||||||
|
}
|
||||||
124
time.c
Normal file
124
time.c
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
#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 "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static Channel* ctimer; /* chan(Timer*)[100] */
|
||||||
|
static Timer *timer;
|
||||||
|
|
||||||
|
static
|
||||||
|
uint
|
||||||
|
msec(void)
|
||||||
|
{
|
||||||
|
return nsec()/1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timerstop(Timer *t)
|
||||||
|
{
|
||||||
|
t->next = timer;
|
||||||
|
timer = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timercancel(Timer *t)
|
||||||
|
{
|
||||||
|
t->cancel = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
timerproc(void*)
|
||||||
|
{
|
||||||
|
int i, nt, na, dt, del;
|
||||||
|
Timer **t, *x;
|
||||||
|
uint old, new;
|
||||||
|
|
||||||
|
rfork(RFFDG);
|
||||||
|
threadsetname("TIMERPROC");
|
||||||
|
t = nil;
|
||||||
|
na = 0;
|
||||||
|
nt = 0;
|
||||||
|
old = msec();
|
||||||
|
for(;;){
|
||||||
|
sleep(1); /* will sleep minimum incr */
|
||||||
|
new = msec();
|
||||||
|
dt = new-old;
|
||||||
|
old = new;
|
||||||
|
if(dt < 0) /* timer wrapped; go around, losing a tick */
|
||||||
|
continue;
|
||||||
|
for(i=0; i<nt; i++){
|
||||||
|
x = t[i];
|
||||||
|
x->dt -= dt;
|
||||||
|
del = 0;
|
||||||
|
if(x->cancel){
|
||||||
|
timerstop(x);
|
||||||
|
del = 1;
|
||||||
|
}else if(x->dt <= 0){
|
||||||
|
/*
|
||||||
|
* avoid possible deadlock if client is
|
||||||
|
* now sending on ctimer
|
||||||
|
*/
|
||||||
|
if(nbsendul(x->c, 0) > 0)
|
||||||
|
del = 1;
|
||||||
|
}
|
||||||
|
if(del){
|
||||||
|
memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]);
|
||||||
|
--nt;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(nt == 0){
|
||||||
|
x = recvp(ctimer);
|
||||||
|
gotit:
|
||||||
|
if(nt == na){
|
||||||
|
na += 10;
|
||||||
|
t = realloc(t, na*sizeof(Timer*));
|
||||||
|
if(t == nil)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
t[nt++] = x;
|
||||||
|
old = msec();
|
||||||
|
}
|
||||||
|
if(nbrecv(ctimer, &x) > 0)
|
||||||
|
goto gotit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timerinit(void)
|
||||||
|
{
|
||||||
|
ctimer = chancreate(sizeof(Timer*), 100);
|
||||||
|
proccreate(timerproc, nil, STACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* timeralloc() and timerfree() don't lock, so can only be
|
||||||
|
* called from the main proc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Timer*
|
||||||
|
timerstart(int dt)
|
||||||
|
{
|
||||||
|
Timer *t;
|
||||||
|
|
||||||
|
t = timer;
|
||||||
|
if(t)
|
||||||
|
timer = timer->next;
|
||||||
|
else{
|
||||||
|
t = emalloc(sizeof(Timer));
|
||||||
|
t->c = chancreate(sizeof(int), 0);
|
||||||
|
}
|
||||||
|
t->next = nil;
|
||||||
|
t->dt = dt;
|
||||||
|
t->cancel = FALSE;
|
||||||
|
sendp(ctimer, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
159
util.c
Normal file
159
util.c
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
#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 "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
|
||||||
|
{
|
||||||
|
uchar *q;
|
||||||
|
Rune *s;
|
||||||
|
int j, w;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Always guaranteed that n bytes may be interpreted
|
||||||
|
* without worrying about partial runes. This may mean
|
||||||
|
* reading up to UTFmax-1 more bytes than n; the caller
|
||||||
|
* knows this. If n is a firm limit, the caller should
|
||||||
|
* set p[n] = 0.
|
||||||
|
*/
|
||||||
|
q = (uchar*)p;
|
||||||
|
s = r;
|
||||||
|
for(j=0; j<n; j+=w){
|
||||||
|
if(*q < Runeself){
|
||||||
|
w = 1;
|
||||||
|
*s = *q++;
|
||||||
|
}else{
|
||||||
|
w = chartorune(s, (char*)q);
|
||||||
|
q += w;
|
||||||
|
}
|
||||||
|
if(*s)
|
||||||
|
s++;
|
||||||
|
else if(nulls)
|
||||||
|
*nulls = TRUE;
|
||||||
|
}
|
||||||
|
*nb = (char*)q-p;
|
||||||
|
*nr = s-r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
error(char *s)
|
||||||
|
{
|
||||||
|
fprint(2, "rio: %s: %r\n", s);
|
||||||
|
if(errorshouldabort)
|
||||||
|
abort();
|
||||||
|
threadexitsall("error");
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
erealloc(void *p, uint n)
|
||||||
|
{
|
||||||
|
p = realloc(p, n);
|
||||||
|
if(p == nil)
|
||||||
|
error("realloc failed");
|
||||||
|
setrealloctag(p, getcallerpc(&p));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
emalloc(uint n)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = malloc(n);
|
||||||
|
if(p == nil)
|
||||||
|
error("malloc failed");
|
||||||
|
setmalloctag(p, getcallerpc(&n));
|
||||||
|
memset(p, 0, n);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
estrdup(char *s)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = malloc(strlen(s)+1);
|
||||||
|
if(p == nil)
|
||||||
|
error("strdup failed");
|
||||||
|
setmalloctag(p, getcallerpc(&s));
|
||||||
|
strcpy(p, s);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isalnum(Rune c)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Hard to get absolutely right. Use what we know about ASCII
|
||||||
|
* and assume anything above the Latin control characters is
|
||||||
|
* potentially an alphanumeric.
|
||||||
|
*/
|
||||||
|
if(c <= ' ')
|
||||||
|
return FALSE;
|
||||||
|
if(0x7F<=c && c<=0xA0)
|
||||||
|
return FALSE;
|
||||||
|
if(utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", c))
|
||||||
|
return FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isspace(Rune c)
|
||||||
|
{
|
||||||
|
return c == 0 || c == ' ' || c == '\t' ||
|
||||||
|
c == '\n' || c == '\r' || c == '\v';
|
||||||
|
}
|
||||||
|
|
||||||
|
Rune*
|
||||||
|
strrune(Rune *s, Rune c)
|
||||||
|
{
|
||||||
|
Rune c1;
|
||||||
|
|
||||||
|
if(c == 0) {
|
||||||
|
while(*s++)
|
||||||
|
;
|
||||||
|
return s-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(c1 = *s++)
|
||||||
|
if(c1 == c)
|
||||||
|
return s-1;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
min(int a, int b)
|
||||||
|
{
|
||||||
|
if(a < b)
|
||||||
|
return a;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
max(int a, int b)
|
||||||
|
{
|
||||||
|
if(a > b)
|
||||||
|
return a;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
runetobyte(Rune *r, int n, int *ip)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int m;
|
||||||
|
|
||||||
|
s = emalloc(n*UTFmax+1);
|
||||||
|
m = snprint(s, n*UTFmax+1, "%.*S", n, r);
|
||||||
|
*ip = m;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
500
wctl.c
Normal file
500
wctl.c
Normal file
|
|
@ -0,0 +1,500 @@
|
||||||
|
#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"
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
char Ebadwr[] = "bad rectangle in wctl request";
|
||||||
|
char Ewalloc[] = "window allocation failed in wctl request";
|
||||||
|
|
||||||
|
/* >= Top are disallowed if mouse button is pressed */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
New,
|
||||||
|
Resize,
|
||||||
|
Move,
|
||||||
|
Scroll,
|
||||||
|
Noscroll,
|
||||||
|
Set,
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
|
Current,
|
||||||
|
Hide,
|
||||||
|
Unhide,
|
||||||
|
Delete,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *cmds[] = {
|
||||||
|
[New] = "new",
|
||||||
|
[Resize] = "resize",
|
||||||
|
[Move] = "move",
|
||||||
|
[Scroll] = "scroll",
|
||||||
|
[Noscroll] = "noscroll",
|
||||||
|
[Set] = "set",
|
||||||
|
[Top] = "top",
|
||||||
|
[Bottom] = "bottom",
|
||||||
|
[Current] = "current",
|
||||||
|
[Hide] = "hide",
|
||||||
|
[Unhide] = "unhide",
|
||||||
|
[Delete] = "delete",
|
||||||
|
nil
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Cd,
|
||||||
|
Deltax,
|
||||||
|
Deltay,
|
||||||
|
Hidden,
|
||||||
|
Id,
|
||||||
|
Maxx,
|
||||||
|
Maxy,
|
||||||
|
Minx,
|
||||||
|
Miny,
|
||||||
|
PID,
|
||||||
|
R,
|
||||||
|
Scrolling,
|
||||||
|
Noscrolling,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *params[] = {
|
||||||
|
[Cd] = "-cd",
|
||||||
|
[Deltax] = "-dx",
|
||||||
|
[Deltay] = "-dy",
|
||||||
|
[Hidden] = "-hide",
|
||||||
|
[Id] = "-id",
|
||||||
|
[Maxx] = "-maxx",
|
||||||
|
[Maxy] = "-maxy",
|
||||||
|
[Minx] = "-minx",
|
||||||
|
[Miny] = "-miny",
|
||||||
|
[PID] = "-pid",
|
||||||
|
[R] = "-r",
|
||||||
|
[Scrolling] = "-scroll",
|
||||||
|
[Noscrolling] = "-noscroll",
|
||||||
|
nil
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that newly created window will be of manageable size
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
goodrect(Rectangle r)
|
||||||
|
{
|
||||||
|
if(badrect(r) || !eqrect(canonrect(r), r))
|
||||||
|
return 0;
|
||||||
|
/* reasonable sizes only please */
|
||||||
|
if(Dx(r) > BIG*Dx(screen->r))
|
||||||
|
return 0;
|
||||||
|
if(Dy(r) > BIG*Dy(screen->r))
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* the height has to be big enough to fit one line of text.
|
||||||
|
* that includes the border on each side with an extra pixel
|
||||||
|
* so that the text is still drawn
|
||||||
|
*/
|
||||||
|
if(Dx(r) < 100 || Dy(r) < 2*(Borderwidth+1)+font->height)
|
||||||
|
return 0;
|
||||||
|
/* window must be on screen */
|
||||||
|
if(!rectXrect(screen->r, r))
|
||||||
|
return 0;
|
||||||
|
/* must have some screen and border visible so we can move it out of the way */
|
||||||
|
if(rectinrect(screen->r, insetrect(r, Borderwidth)))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
word(char **sp, char *tab[])
|
||||||
|
{
|
||||||
|
char *s, *t;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
s = *sp;
|
||||||
|
while(isspace(*s))
|
||||||
|
s++;
|
||||||
|
t = s;
|
||||||
|
while(*s!='\0' && !isspace(*s))
|
||||||
|
s++;
|
||||||
|
for(i=0; tab[i]!=nil; i++)
|
||||||
|
if(strncmp(tab[i], t, strlen(tab[i])) == 0){
|
||||||
|
*sp = s;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
set(int sign, int neg, int abs, int pos)
|
||||||
|
{
|
||||||
|
if(sign < 0)
|
||||||
|
return neg;
|
||||||
|
if(sign > 0)
|
||||||
|
return pos;
|
||||||
|
return abs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
newrect(void)
|
||||||
|
{
|
||||||
|
static int i = 0;
|
||||||
|
int minx, miny, dx, dy;
|
||||||
|
|
||||||
|
dx = min(600, Dx(screen->r) - 2*Borderwidth);
|
||||||
|
dy = min(400, Dy(screen->r) - 2*Borderwidth);
|
||||||
|
minx = 32 + 16*i;
|
||||||
|
miny = 32 + 16*i;
|
||||||
|
i++;
|
||||||
|
i %= 10;
|
||||||
|
|
||||||
|
return Rect(minx, miny, minx+dx, miny+dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
shift(int *minp, int *maxp, int min, int max)
|
||||||
|
{
|
||||||
|
if(*maxp > max){
|
||||||
|
*minp += max-*maxp;
|
||||||
|
*maxp = max;
|
||||||
|
}
|
||||||
|
if(*minp < min){
|
||||||
|
*maxp += min-*minp;
|
||||||
|
if(*maxp > max)
|
||||||
|
*maxp = max;
|
||||||
|
*minp = min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
rectonscreen(Rectangle r)
|
||||||
|
{
|
||||||
|
shift(&r.min.x, &r.max.x, screen->r.min.x, screen->r.max.x);
|
||||||
|
shift(&r.min.y, &r.max.y, screen->r.min.y, screen->r.max.y);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* permit square brackets, in the manner of %R */
|
||||||
|
int
|
||||||
|
riostrtol(char *s, char **t)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while(*s!='\0' && (*s==' ' || *s=='\t' || *s=='['))
|
||||||
|
s++;
|
||||||
|
if(*s == '[')
|
||||||
|
s++;
|
||||||
|
n = strtol(s, t, 10);
|
||||||
|
if(*t != s)
|
||||||
|
while((*t)[0] == ']')
|
||||||
|
(*t)++;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
parsewctl(char **argp, Rectangle r, Rectangle *rp, int *pidp, int *idp, int *hiddenp, int *scrollingp, char **cdp, char *s, char *err)
|
||||||
|
{
|
||||||
|
int cmd, n, nt, param, xy, sign;
|
||||||
|
char *f[2], *t;
|
||||||
|
|
||||||
|
*pidp = 0;
|
||||||
|
*hiddenp = 0;
|
||||||
|
*scrollingp = scrolling;
|
||||||
|
*cdp = nil;
|
||||||
|
cmd = word(&s, cmds);
|
||||||
|
if(cmd < 0){
|
||||||
|
strcpy(err, "unrecognized wctl command");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(cmd == New)
|
||||||
|
r = newrect();
|
||||||
|
|
||||||
|
strcpy(err, "missing or bad wctl parameter");
|
||||||
|
while((param = word(&s, params)) >= 0){
|
||||||
|
switch(param){ /* special cases */
|
||||||
|
case Hidden:
|
||||||
|
*hiddenp = 1;
|
||||||
|
continue;
|
||||||
|
case Scrolling:
|
||||||
|
*scrollingp = 1;
|
||||||
|
continue;
|
||||||
|
case Noscrolling:
|
||||||
|
*scrollingp = 0;
|
||||||
|
continue;
|
||||||
|
case R:
|
||||||
|
r.min.x = riostrtol(s, &t);
|
||||||
|
if(t == s)
|
||||||
|
return -1;
|
||||||
|
s = t;
|
||||||
|
r.min.y = riostrtol(s, &t);
|
||||||
|
if(t == s)
|
||||||
|
return -1;
|
||||||
|
s = t;
|
||||||
|
r.max.x = riostrtol(s, &t);
|
||||||
|
if(t == s)
|
||||||
|
return -1;
|
||||||
|
s = t;
|
||||||
|
r.max.y = riostrtol(s, &t);
|
||||||
|
if(t == s)
|
||||||
|
return -1;
|
||||||
|
s = t;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
while(isspace(*s))
|
||||||
|
s++;
|
||||||
|
if(param == Cd){
|
||||||
|
*cdp = s;
|
||||||
|
if((nt = gettokens(*cdp, f, nelem(f), " \t\r\n\v\f")) < 1)
|
||||||
|
return -1;
|
||||||
|
n = strlen(*cdp);
|
||||||
|
if((*cdp)[0] == '\'' && (*cdp)[n-1] == '\'')
|
||||||
|
((*cdp)++)[n-1] = '\0'; /* drop quotes */
|
||||||
|
s += n+(nt-1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sign = 0;
|
||||||
|
if(*s == '-'){
|
||||||
|
sign = -1;
|
||||||
|
s++;
|
||||||
|
}else if(*s == '+'){
|
||||||
|
sign = +1;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
if(!isdigit(*s))
|
||||||
|
return -1;
|
||||||
|
xy = riostrtol(s, &s);
|
||||||
|
switch(param){
|
||||||
|
case -1:
|
||||||
|
strcpy(err, "unrecognized wctl parameter");
|
||||||
|
return -1;
|
||||||
|
case Minx:
|
||||||
|
r.min.x = set(sign, r.min.x-xy, xy, r.min.x+xy);
|
||||||
|
break;
|
||||||
|
case Miny:
|
||||||
|
r.min.y = set(sign, r.min.y-xy, xy, r.min.y+xy);
|
||||||
|
break;
|
||||||
|
case Maxx:
|
||||||
|
r.max.x = set(sign, r.max.x-xy, xy, r.max.x+xy);
|
||||||
|
break;
|
||||||
|
case Maxy:
|
||||||
|
r.max.y = set(sign, r.max.y-xy, xy, r.max.y+xy);
|
||||||
|
break;
|
||||||
|
case Deltax:
|
||||||
|
r.max.x = set(sign, r.max.x-xy, r.min.x+xy, r.max.x+xy);
|
||||||
|
break;
|
||||||
|
case Deltay:
|
||||||
|
r.max.y = set(sign, r.max.y-xy, r.min.y+xy, r.max.y+xy);
|
||||||
|
break;
|
||||||
|
case Id:
|
||||||
|
if(idp != nil)
|
||||||
|
*idp = xy;
|
||||||
|
break;
|
||||||
|
case PID:
|
||||||
|
if(pidp != nil)
|
||||||
|
*pidp = xy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*rp = rectonscreen(rectaddpt(r, screen->r.min));
|
||||||
|
|
||||||
|
while(isspace(*s))
|
||||||
|
s++;
|
||||||
|
if(cmd!=New && *s!='\0'){
|
||||||
|
strcpy(err, "extraneous text in wctl message");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argp)
|
||||||
|
*argp = s;
|
||||||
|
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wctlnew(Rectangle rect, char *arg, int pid, int hideit, int scrollit, char *dir, char *err)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
Image *i;
|
||||||
|
|
||||||
|
if(!goodrect(rect)){
|
||||||
|
strcpy(err, Ebadwr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
argv = emalloc(4*sizeof(char*));
|
||||||
|
argv[0] = "rc";
|
||||||
|
argv[1] = "-c";
|
||||||
|
while(isspace(*arg))
|
||||||
|
arg++;
|
||||||
|
if(*arg == '\0'){
|
||||||
|
argv[1] = "-i";
|
||||||
|
argv[2] = nil;
|
||||||
|
}else{
|
||||||
|
argv[2] = arg;
|
||||||
|
argv[3] = nil;
|
||||||
|
}
|
||||||
|
if(hideit)
|
||||||
|
i = allocimage(display, rect, screen->chan, 0, DNofill);
|
||||||
|
else
|
||||||
|
i = allocwindow(wscreen, rect, Refbackup, DNofill);
|
||||||
|
if(i == nil){
|
||||||
|
strcpy(err, Ewalloc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
new(i, hideit, scrollit, pid, dir, "/bin/rc", argv);
|
||||||
|
|
||||||
|
free(argv); /* when new() returns, argv and args have been copied */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wctlcmd(Window *w, Rectangle r, int cmd, char *err)
|
||||||
|
{
|
||||||
|
Image *i;
|
||||||
|
|
||||||
|
switch(cmd){
|
||||||
|
case Move:
|
||||||
|
r = Rect(r.min.x, r.min.y, r.min.x+Dx(w->screenr), r.min.y+Dy(w->screenr));
|
||||||
|
r = rectonscreen(r);
|
||||||
|
/* fall through */
|
||||||
|
case Resize:
|
||||||
|
if(!goodrect(r)){
|
||||||
|
strcpy(err, Ebadwr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(Dx(w->screenr) > 0){
|
||||||
|
if(eqrect(r, w->screenr))
|
||||||
|
return 1;
|
||||||
|
if(w != input){
|
||||||
|
strcpy(err, "window not current");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
i = allocwindow(wscreen, r, Refbackup, DNofill);
|
||||||
|
} else { /* hidden */
|
||||||
|
if(eqrect(r, w->i->r))
|
||||||
|
return 1;
|
||||||
|
wuncurrent(w);
|
||||||
|
i = allocimage(display, r, w->i->chan, 0, DNofill);
|
||||||
|
r = ZR;
|
||||||
|
}
|
||||||
|
if(i == nil){
|
||||||
|
strcpy(err, Ewalloc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wsendctlmesg(w, Reshaped, r, i);
|
||||||
|
return 1;
|
||||||
|
case Scroll:
|
||||||
|
w->scrolling = 1;
|
||||||
|
wshow(w, w->nr);
|
||||||
|
wsendctlmesg(w, Wakeup, ZR, nil);
|
||||||
|
return 1;
|
||||||
|
case Noscroll:
|
||||||
|
w->scrolling = 0;
|
||||||
|
wsendctlmesg(w, Wakeup, ZR, nil);
|
||||||
|
return 1;
|
||||||
|
case Top:
|
||||||
|
wtopme(w);
|
||||||
|
return 1;
|
||||||
|
case Bottom:
|
||||||
|
wbottomme(w);
|
||||||
|
return 1;
|
||||||
|
case Current:
|
||||||
|
if(Dx(w->screenr)<=0){
|
||||||
|
strcpy(err, "window is hidden");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
wcurrent(w);
|
||||||
|
wtopme(w);
|
||||||
|
wsendctlmesg(w, Topped, ZR, nil);
|
||||||
|
return 1;
|
||||||
|
case Hide:
|
||||||
|
switch(whide(w)){
|
||||||
|
case -1:
|
||||||
|
strcpy(err, "window already hidden");
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
|
strcpy(err, "hide failed");
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
case Unhide:
|
||||||
|
switch(wunhide(w)){
|
||||||
|
case -1:
|
||||||
|
strcpy(err, "window not hidden");
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
|
strcpy(err, "hide failed");
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
case Delete:
|
||||||
|
wsendctlmesg(w, Deleted, ZR, nil);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(err, "invalid wctl message");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
writewctl(Xfid *x, char *err)
|
||||||
|
{
|
||||||
|
int cnt, cmd, id, hideit, scrollit, pid;
|
||||||
|
char *arg, *dir;
|
||||||
|
Rectangle r;
|
||||||
|
Window *w;
|
||||||
|
|
||||||
|
w = x->f->w;
|
||||||
|
cnt = x->count;
|
||||||
|
x->data[cnt] = '\0';
|
||||||
|
id = 0;
|
||||||
|
|
||||||
|
if(w == nil)
|
||||||
|
r = ZR;
|
||||||
|
else
|
||||||
|
r = rectsubpt(w->screenr, screen->r.min);
|
||||||
|
cmd = parsewctl(&arg, r, &r, &pid, &id, &hideit, &scrollit, &dir, x->data, err);
|
||||||
|
if(cmd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(id != 0){
|
||||||
|
w = wlookid(id);
|
||||||
|
if(w == 0){
|
||||||
|
strcpy(err, "no such window id");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(w == nil && cmd != New){
|
||||||
|
strcpy(err, "command needs to be run within a window");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(cmd){
|
||||||
|
case New:
|
||||||
|
return wctlnew(r, arg, pid, hideit, scrollit, dir, err);
|
||||||
|
case Set:
|
||||||
|
if(pid > 0)
|
||||||
|
wsetpid(w, pid, 0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
incref(w);
|
||||||
|
id = wctlcmd(w, r, cmd, err);
|
||||||
|
wclose(w);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
916
xfid.c
Normal file
916
xfid.c
Normal file
|
|
@ -0,0 +1,916 @@
|
||||||
|
#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"
|
||||||
|
|
||||||
|
char Einuse[] = "file in use";
|
||||||
|
char Edeleted[] = "window deleted";
|
||||||
|
char Etooshort[] = "buffer too small";
|
||||||
|
char Eshort[] = "short i/o request";
|
||||||
|
char Elong[] = "snarf buffer too long";
|
||||||
|
char Eunkid[] = "unknown id in attach";
|
||||||
|
char Ebadrect[] = "bad rectangle in attach";
|
||||||
|
char Ewindow[] = "cannot make window";
|
||||||
|
char Enowindow[] = "window has no image";
|
||||||
|
char Ebadmouse[] = "bad format on /dev/mouse";
|
||||||
|
|
||||||
|
extern char Eperm[];
|
||||||
|
extern char Enomem[];
|
||||||
|
|
||||||
|
static Xfid *xfidfree;
|
||||||
|
static Xfid *xfid;
|
||||||
|
static Channel *cxfidalloc; /* chan(Xfid*) */
|
||||||
|
static Channel *cxfidfree; /* chan(Xfid*) */
|
||||||
|
|
||||||
|
static char *tsnarf;
|
||||||
|
static int ntsnarf;
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidallocthread(void*)
|
||||||
|
{
|
||||||
|
Xfid *x;
|
||||||
|
enum { Alloc, Free, N };
|
||||||
|
static Alt alts[N+1];
|
||||||
|
|
||||||
|
alts[Alloc].c = cxfidalloc;
|
||||||
|
alts[Alloc].v = nil;
|
||||||
|
alts[Alloc].op = CHANRCV;
|
||||||
|
alts[Free].c = cxfidfree;
|
||||||
|
alts[Free].v = &x;
|
||||||
|
alts[Free].op = CHANRCV;
|
||||||
|
alts[N].op = CHANEND;
|
||||||
|
for(;;){
|
||||||
|
switch(alt(alts)){
|
||||||
|
case Alloc:
|
||||||
|
x = xfidfree;
|
||||||
|
if(x)
|
||||||
|
xfidfree = x->free;
|
||||||
|
else{
|
||||||
|
x = emalloc(sizeof(Xfid));
|
||||||
|
x->c = chancreate(sizeof(void(*)(Xfid*)), 0);
|
||||||
|
x->flushc = chancreate(sizeof(int), 0); /* notification only; no data */
|
||||||
|
x->flushtag = -1;
|
||||||
|
x->next = xfid;
|
||||||
|
xfid = x;
|
||||||
|
threadcreate(xfidctl, x, 16384);
|
||||||
|
}
|
||||||
|
if(x->ref != 0){
|
||||||
|
fprint(2, "%p incref %ld\n", x, x->ref);
|
||||||
|
error("incref");
|
||||||
|
}
|
||||||
|
if(x->flushtag != -1)
|
||||||
|
error("flushtag in allocate");
|
||||||
|
incref(x);
|
||||||
|
sendp(cxfidalloc, x);
|
||||||
|
break;
|
||||||
|
case Free:
|
||||||
|
if(x->ref != 0){
|
||||||
|
fprint(2, "%p decref %ld\n", x, x->ref);
|
||||||
|
error("decref");
|
||||||
|
}
|
||||||
|
if(x->flushtag != -1)
|
||||||
|
error("flushtag in free");
|
||||||
|
x->free = xfidfree;
|
||||||
|
xfidfree = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Channel*
|
||||||
|
xfidinit(void)
|
||||||
|
{
|
||||||
|
cxfidalloc = chancreate(sizeof(Xfid*), 0);
|
||||||
|
cxfidfree = chancreate(sizeof(Xfid*), 0);
|
||||||
|
threadcreate(xfidallocthread, nil, STACK);
|
||||||
|
return cxfidalloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidctl(void *arg)
|
||||||
|
{
|
||||||
|
Xfid *x;
|
||||||
|
void (*f)(Xfid*);
|
||||||
|
|
||||||
|
x = arg;
|
||||||
|
threadsetname("xfid.%p", x);
|
||||||
|
for(;;){
|
||||||
|
f = recvp(x->c);
|
||||||
|
if(f){
|
||||||
|
x->flushtag = x->tag;
|
||||||
|
(*f)(x);
|
||||||
|
}
|
||||||
|
if(decref(x) == 0)
|
||||||
|
sendp(cxfidfree, x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidflush(Xfid *x)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
Xfid *xf;
|
||||||
|
|
||||||
|
for(xf=xfid; xf; xf=xf->next)
|
||||||
|
if(xf->flushtag == x->oldtag){
|
||||||
|
incref(xf); /* to hold data structures up at tail of synchronization */
|
||||||
|
if(xf->ref == 1)
|
||||||
|
error("ref 1 in flush");
|
||||||
|
xf->flushtag = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* take over flushtag so follow up flushes wait for us */
|
||||||
|
x->flushtag = x->oldtag;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wakeup filsysflush() in the filsysproc so the next
|
||||||
|
* flush can come in.
|
||||||
|
*/
|
||||||
|
sendul(x->fs->csyncflush, 0);
|
||||||
|
|
||||||
|
if(xf){
|
||||||
|
enum { Done, Flush, End };
|
||||||
|
Alt alts[End+1];
|
||||||
|
void *f;
|
||||||
|
int z;
|
||||||
|
|
||||||
|
z = 0;
|
||||||
|
f = nil;
|
||||||
|
|
||||||
|
alts[Done].c = xf->c;
|
||||||
|
alts[Done].v = &f;
|
||||||
|
alts[Done].op = CHANSND;
|
||||||
|
alts[Flush].c = xf->flushc;
|
||||||
|
alts[Flush].v = &z;
|
||||||
|
alts[Flush].op = CHANSND;
|
||||||
|
alts[End].op = CHANEND;
|
||||||
|
|
||||||
|
while(alt(alts) != Done)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
if(nbrecv(x->flushc, nil)){
|
||||||
|
filsyscancel(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
filsysrespond(x->fs, x, &t, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidattach(Xfid *x)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
int id, hideit, scrollit;
|
||||||
|
Window *w;
|
||||||
|
char *err, *n, *dir, errbuf[ERRMAX];
|
||||||
|
int pid, newlymade;
|
||||||
|
Rectangle r;
|
||||||
|
Image *i;
|
||||||
|
|
||||||
|
t.qid = x->f->qid;
|
||||||
|
qlock(&all);
|
||||||
|
w = nil;
|
||||||
|
err = Eunkid;
|
||||||
|
dir = nil;
|
||||||
|
newlymade = FALSE;
|
||||||
|
hideit = 0;
|
||||||
|
scrollit = scrolling;
|
||||||
|
|
||||||
|
if(x->aname[0] == 'N'){ /* N 100,100, 200, 200 - old syntax */
|
||||||
|
n = x->aname+1;
|
||||||
|
pid = strtoul(n, &n, 0);
|
||||||
|
if(*n == ',')
|
||||||
|
n++;
|
||||||
|
r.min.x = strtoul(n, &n, 0);
|
||||||
|
if(*n == ',')
|
||||||
|
n++;
|
||||||
|
r.min.y = strtoul(n, &n, 0);
|
||||||
|
if(*n == ',')
|
||||||
|
n++;
|
||||||
|
r.max.x = strtoul(n, &n, 0);
|
||||||
|
if(*n == ',')
|
||||||
|
n++;
|
||||||
|
r.max.y = strtoul(n, &n, 0);
|
||||||
|
Allocate:
|
||||||
|
if(!goodrect(r))
|
||||||
|
err = Ebadrect;
|
||||||
|
else{
|
||||||
|
if(hideit)
|
||||||
|
i = allocimage(display, r, screen->chan, 0, DNofill);
|
||||||
|
else
|
||||||
|
i = allocwindow(wscreen, r, Refbackup, DNofill);
|
||||||
|
if(i){
|
||||||
|
if(pid == 0)
|
||||||
|
pid = -1; /* make sure we don't pop a shell! - UGH */
|
||||||
|
w = new(i, hideit, scrollit, pid, dir, nil, nil);
|
||||||
|
newlymade = TRUE;
|
||||||
|
}else
|
||||||
|
err = Ewindow;
|
||||||
|
}
|
||||||
|
}else if(strncmp(x->aname, "new", 3) == 0){ /* new -dx -dy - new syntax, as in wctl */
|
||||||
|
pid = 0;
|
||||||
|
if(parsewctl(nil, ZR, &r, &pid, nil, &hideit, &scrollit, &dir, x->aname, errbuf) < 0)
|
||||||
|
err = errbuf;
|
||||||
|
else
|
||||||
|
goto Allocate;
|
||||||
|
}else if(strncmp(x->aname, "none", 4) == 0){
|
||||||
|
x->f->w = nil;
|
||||||
|
goto Done;
|
||||||
|
}else{
|
||||||
|
id = atoi(x->aname);
|
||||||
|
w = wlookid(id);
|
||||||
|
}
|
||||||
|
x->f->w = w;
|
||||||
|
if(w == nil){
|
||||||
|
qunlock(&all);
|
||||||
|
x->f->busy = FALSE;
|
||||||
|
filsysrespond(x->fs, x, &t, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!newlymade) /* counteract dec() in winshell() */
|
||||||
|
incref(w);
|
||||||
|
Done:
|
||||||
|
qunlock(&all);
|
||||||
|
filsysrespond(x->fs, x, &t, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidopen(Xfid *x)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
Window *w;
|
||||||
|
|
||||||
|
w = x->f->w;
|
||||||
|
if(w != nil && w->deleted){
|
||||||
|
filsysrespond(x->fs, x, &t, Edeleted);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(FILE(x->f->qid)){
|
||||||
|
case Qtext:
|
||||||
|
if(x->mode&OTRUNC)
|
||||||
|
wsendctlmesg(w, Truncate, ZR, nil);
|
||||||
|
break;
|
||||||
|
case Qconsctl:
|
||||||
|
if(w->ctlopen){
|
||||||
|
filsysrespond(x->fs, x, &t, Einuse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w->ctlopen = TRUE;
|
||||||
|
break;
|
||||||
|
case Qkbd:
|
||||||
|
if(w->kbdopen){
|
||||||
|
filsysrespond(x->fs, x, &t, Einuse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w->kbdopen = TRUE;
|
||||||
|
break;
|
||||||
|
case Qmouse:
|
||||||
|
if(w->mouseopen){
|
||||||
|
filsysrespond(x->fs, x, &t, Einuse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Reshaped: there's a race if the appl. opens the
|
||||||
|
* window, is resized, and then opens the mouse,
|
||||||
|
* but that's rare. The alternative is to generate
|
||||||
|
* a resized event every time a new program starts
|
||||||
|
* up in a window that has been resized since the
|
||||||
|
* dawn of time. We choose the lesser evil.
|
||||||
|
*/
|
||||||
|
w->resized = FALSE;
|
||||||
|
w->mouseopen = TRUE;
|
||||||
|
break;
|
||||||
|
case Qsnarf:
|
||||||
|
if(x->mode==ORDWR || x->mode==OWRITE)
|
||||||
|
ntsnarf = 0;
|
||||||
|
break;
|
||||||
|
case Qwctl:
|
||||||
|
if(w != nil && (x->mode==OREAD || x->mode==ORDWR)){
|
||||||
|
/*
|
||||||
|
* It would be much nicer to implement fan-out for wctl reads,
|
||||||
|
* so multiple people can see the resizings, but rio just isn't
|
||||||
|
* structured for that. It's structured for /dev/cons, which gives
|
||||||
|
* alternate data to alternate readers. So to keep things sane for
|
||||||
|
* wctl, we compromise and give an error if two people try to
|
||||||
|
* open it. Apologies.
|
||||||
|
*/
|
||||||
|
if(w->wctlopen){
|
||||||
|
filsysrespond(x->fs, x, &t, Einuse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w->wctlopen = TRUE;
|
||||||
|
w->wctlready = 1;
|
||||||
|
wsendctlmesg(w, Wakeup, ZR, nil);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Qtap:
|
||||||
|
if((x->mode == OWRITE || x->mode == ORDWR) && fromtap != nil){
|
||||||
|
filsysrespond(x->fs, x, &t, Einuse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(x->mode == OREAD || x->mode == ORDWR){
|
||||||
|
if(totap != nil){
|
||||||
|
filsysrespond(x->fs, x, &t, Einuse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
totap = chancreate(sizeof(char*), 32);
|
||||||
|
sendp(opentap, totap);
|
||||||
|
}
|
||||||
|
if(x->mode == OWRITE || x->mode == ORDWR){
|
||||||
|
fromtap = chancreate(sizeof(char*), 32);
|
||||||
|
sendp(opentap, fromtap);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t.qid = x->f->qid;
|
||||||
|
t.iounit = messagesize-IOHDRSZ;
|
||||||
|
x->f->open = TRUE;
|
||||||
|
x->f->mode = x->mode;
|
||||||
|
filsysrespond(x->fs, x, &t, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidclose(Xfid *x)
|
||||||
|
{
|
||||||
|
Fcall t;
|
||||||
|
Window *w;
|
||||||
|
int nb, nulls;
|
||||||
|
|
||||||
|
w = x->f->w;
|
||||||
|
switch(FILE(x->f->qid)){
|
||||||
|
case Qconsctl:
|
||||||
|
if(w->rawing){
|
||||||
|
w->rawing = FALSE;
|
||||||
|
wsendctlmesg(w, Rawoff, ZR, nil);
|
||||||
|
}
|
||||||
|
if(w->holding){
|
||||||
|
w->holding = FALSE;
|
||||||
|
wsendctlmesg(w, Holdoff, ZR, nil);
|
||||||
|
}
|
||||||
|
w->ctlopen = FALSE;
|
||||||
|
break;
|
||||||
|
case Qcursor:
|
||||||
|
w->cursorp = nil;
|
||||||
|
wsetcursor(w, FALSE);
|
||||||
|
break;
|
||||||
|
case Qkbd:
|
||||||
|
w->kbdopen = FALSE;
|
||||||
|
break;
|
||||||
|
case Qmouse:
|
||||||
|
w->resized = FALSE;
|
||||||
|
w->mouseopen = FALSE;
|
||||||
|
w->winnameread = FALSE;
|
||||||
|
if(w->i != nil)
|
||||||
|
wsendctlmesg(w, Refresh, w->i->r, nil);
|
||||||
|
break;
|
||||||
|
/* odd behavior but really ok: replace snarf buffer when /dev/snarf is closed */
|
||||||
|
case Qsnarf:
|
||||||
|
if(x->f->mode==ORDWR || x->f->mode==OWRITE){
|
||||||
|
snarf = runerealloc(snarf, ntsnarf+1);
|
||||||
|
cvttorunes(tsnarf, ntsnarf, snarf, &nb, &nsnarf, &nulls);
|
||||||
|
ntsnarf = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Qwctl:
|
||||||
|
if(w != nil && (x->f->mode==OREAD || x->f->mode==ORDWR))
|
||||||
|
w->wctlopen = FALSE;
|
||||||
|
break;
|
||||||
|
case Qtap:
|
||||||
|
if(fromtap != nil && (x->f->mode == OWRITE || x->f->mode == ORDWR))
|
||||||
|
sendp(closetap, fromtap);
|
||||||
|
if(totap != nil && (x->f->mode == OREAD || x->f->mode == ORDWR))
|
||||||
|
sendp(closetap, totap);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(w)
|
||||||
|
wclose(w);
|
||||||
|
filsysrespond(x->fs, x, &t, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidwrite(Xfid *x)
|
||||||
|
{
|
||||||
|
Fcall fc;
|
||||||
|
int cnt, qid, nb, nr;
|
||||||
|
char err[ERRMAX], *p, *e;
|
||||||
|
Point pt;
|
||||||
|
Window *w;
|
||||||
|
Rune *r;
|
||||||
|
Conswritemesg cwm;
|
||||||
|
Stringpair pair;
|
||||||
|
enum { CWdata, CWgone, CWflush, NCW };
|
||||||
|
Alt alts[NCW+1];
|
||||||
|
|
||||||
|
w = x->f->w;
|
||||||
|
if(w != nil && w->deleted){
|
||||||
|
filsysrespond(x->fs, x, &fc, Edeleted);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qid = FILE(x->f->qid);
|
||||||
|
cnt = x->count;
|
||||||
|
x->data[cnt] = 0;
|
||||||
|
switch(qid){
|
||||||
|
case Qcons:
|
||||||
|
case Qtext:
|
||||||
|
alts[CWdata].c = w->conswrite;
|
||||||
|
alts[CWdata].v = &cwm;
|
||||||
|
alts[CWdata].op = CHANRCV;
|
||||||
|
alts[CWgone].c = w->gone;
|
||||||
|
alts[CWgone].v = nil;
|
||||||
|
alts[CWgone].op = CHANRCV;
|
||||||
|
alts[CWflush].c = x->flushc;
|
||||||
|
alts[CWflush].v = nil;
|
||||||
|
alts[CWflush].op = CHANRCV;
|
||||||
|
alts[NCW].op = CHANEND;
|
||||||
|
|
||||||
|
switch(alt(alts)){
|
||||||
|
case CWdata:
|
||||||
|
break;
|
||||||
|
case CWgone:
|
||||||
|
filsysrespond(x->fs, x, &fc, Edeleted);
|
||||||
|
return;
|
||||||
|
case CWflush:
|
||||||
|
filsyscancel(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nr = x->f->nrpart;
|
||||||
|
if(nr > 0){
|
||||||
|
memmove(x->data+nr, x->data, cnt); /* there's room: see malloc in filsysproc */
|
||||||
|
memmove(x->data, x->f->rpart, nr);
|
||||||
|
cnt += nr;
|
||||||
|
}
|
||||||
|
r = runemalloc(cnt);
|
||||||
|
if(r == nil){
|
||||||
|
pair.ns = 0;
|
||||||
|
send(cwm.cw, &pair);
|
||||||
|
filsysrespond(x->fs, x, &fc, Enomem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
x->f->nrpart = 0;
|
||||||
|
cvttorunes(x->data, cnt-UTFmax, r, &nb, &nr, nil);
|
||||||
|
/* approach end of buffer */
|
||||||
|
while(fullrune(x->data+nb, cnt-nb)){
|
||||||
|
nb += chartorune(&r[nr], x->data+nb);
|
||||||
|
if(r[nr])
|
||||||
|
nr++;
|
||||||
|
}
|
||||||
|
if(nb < cnt){
|
||||||
|
memmove(x->f->rpart, x->data+nb, cnt-nb);
|
||||||
|
x->f->nrpart = cnt-nb;
|
||||||
|
}
|
||||||
|
|
||||||
|
pair.s = r;
|
||||||
|
pair.ns = nr;
|
||||||
|
send(cwm.cw, &pair);
|
||||||
|
fc.count = x->count;
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Qconsctl:
|
||||||
|
if(strncmp(x->data, "holdon", 6)==0){
|
||||||
|
if(w->holding++ == 0)
|
||||||
|
wsendctlmesg(w, Holdon, ZR, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strncmp(x->data, "holdoff", 7)==0 && w->holding){
|
||||||
|
if(--w->holding == 0)
|
||||||
|
wsendctlmesg(w, Holdoff, ZR, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strncmp(x->data, "rawon", 5)==0){
|
||||||
|
if(w->holding){
|
||||||
|
w->holding = 0;
|
||||||
|
wsendctlmesg(w, Holdoff, ZR, nil);
|
||||||
|
}
|
||||||
|
if(w->rawing++ == 0)
|
||||||
|
wsendctlmesg(w, Rawon, ZR, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strncmp(x->data, "rawoff", 6)==0 && w->rawing){
|
||||||
|
if(--w->rawing == 0)
|
||||||
|
wsendctlmesg(w, Rawoff, ZR, nil);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filsysrespond(x->fs, x, &fc, "unknown control message");
|
||||||
|
return;
|
||||||
|
|
||||||
|
case Qcursor:
|
||||||
|
if(cnt < 2*4+2*2*16)
|
||||||
|
w->cursorp = nil;
|
||||||
|
else{
|
||||||
|
w->cursor.offset.x = BGLONG(x->data+0*4);
|
||||||
|
w->cursor.offset.y = BGLONG(x->data+1*4);
|
||||||
|
memmove(w->cursor.clr, x->data+2*4, 2*2*16);
|
||||||
|
w->cursorp = &w->cursor;
|
||||||
|
}
|
||||||
|
wsetcursor(w, TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qlabel:
|
||||||
|
p = realloc(w->label, cnt+1);
|
||||||
|
if(p == nil){
|
||||||
|
filsysrespond(x->fs, x, &fc, Enomem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w->label = p;
|
||||||
|
w->label[cnt] = 0;
|
||||||
|
memmove(w->label, x->data, cnt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qmouse:
|
||||||
|
if(w!=input || Dx(w->screenr)<=0)
|
||||||
|
break;
|
||||||
|
if(x->data[0] != 'm'){
|
||||||
|
filsysrespond(x->fs, x, &fc, Ebadmouse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p = nil;
|
||||||
|
pt.x = strtoul(x->data+1, &p, 0);
|
||||||
|
if(p == nil){
|
||||||
|
filsysrespond(x->fs, x, &fc, Eshort);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pt.y = strtoul(p, nil, 0);
|
||||||
|
if(w==input && wpointto(mouse->xy)==w)
|
||||||
|
wsendctlmesg(w, Movemouse, Rpt(pt, pt), nil);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qsnarf:
|
||||||
|
if(cnt == 0)
|
||||||
|
break;
|
||||||
|
/* always append only */
|
||||||
|
if(ntsnarf > MAXSNARF){ /* avoid thrashing when people cut huge text */
|
||||||
|
filsysrespond(x->fs, x, &fc, Elong);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p = realloc(tsnarf, ntsnarf+cnt+1); /* room for NUL */
|
||||||
|
if(p == nil){
|
||||||
|
filsysrespond(x->fs, x, &fc, Enomem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tsnarf = p;
|
||||||
|
memmove(tsnarf+ntsnarf, x->data, cnt);
|
||||||
|
ntsnarf += cnt;
|
||||||
|
snarfversion++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qwdir:
|
||||||
|
if(cnt == 0)
|
||||||
|
break;
|
||||||
|
if(x->data[cnt-1] == '\n'){
|
||||||
|
if(cnt == 1)
|
||||||
|
break;
|
||||||
|
x->data[cnt-1] = '\0';
|
||||||
|
}
|
||||||
|
/* assume data comes in a single write */
|
||||||
|
if(x->data[0] == '/'){
|
||||||
|
p = smprint("%.*s", cnt, x->data);
|
||||||
|
}else{
|
||||||
|
p = smprint("%s/%.*s", w->dir, cnt, x->data);
|
||||||
|
}
|
||||||
|
if(p == nil){
|
||||||
|
filsysrespond(x->fs, x, &fc, Enomem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(w->dir);
|
||||||
|
w->dir = cleanname(p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qwctl:
|
||||||
|
if(writewctl(x, err) < 0){
|
||||||
|
filsysrespond(x->fs, x, &fc, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qtap:
|
||||||
|
if(cnt < 2){
|
||||||
|
filsysrespond(x->fs, x, &fc, "malformed key");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e = x->data + cnt;
|
||||||
|
for(p = x->data; p < e; p += strlen(p)+1){
|
||||||
|
switch(*p){
|
||||||
|
case '\0':
|
||||||
|
fc.count = p - x->data;
|
||||||
|
filsysrespond(x->fs, x, &fc, "null message type");
|
||||||
|
return;
|
||||||
|
case 'z': /* ignore context change */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
chanprint(fromtap, "%s", p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprint(2, "unknown qid %d in write\n", qid);
|
||||||
|
filsysrespond(x->fs, x, &fc, "unknown qid in write");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fc.count = cnt;
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
readwindow(Image *i, char *t, Rectangle r, int offset, int n)
|
||||||
|
{
|
||||||
|
int ww, oo, y, m;
|
||||||
|
uchar *tt;
|
||||||
|
|
||||||
|
ww = bytesperline(r, i->depth);
|
||||||
|
r.min.y += offset/ww;
|
||||||
|
if(r.min.y >= r.max.y)
|
||||||
|
return 0;
|
||||||
|
y = r.min.y + (n + ww-1)/ww;
|
||||||
|
if(y < r.max.y)
|
||||||
|
r.max.y = y;
|
||||||
|
m = ww * Dy(r);
|
||||||
|
oo = offset % ww;
|
||||||
|
if(oo == 0 && n >= m)
|
||||||
|
return unloadimage(i, r, (uchar*)t, n);
|
||||||
|
if((tt = malloc(m)) == nil)
|
||||||
|
return -1;
|
||||||
|
m = unloadimage(i, r, tt, m) - oo;
|
||||||
|
if(m > 0){
|
||||||
|
if(n < m) m = n;
|
||||||
|
memmove(t, tt + oo, m);
|
||||||
|
}
|
||||||
|
free(tt);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xfidread(Xfid *x)
|
||||||
|
{
|
||||||
|
Fcall fc;
|
||||||
|
int n, off, cnt, c;
|
||||||
|
uint qid;
|
||||||
|
char buf[128], *t;
|
||||||
|
char cbuf[30];
|
||||||
|
Window *w;
|
||||||
|
Mouse ms;
|
||||||
|
Rectangle r;
|
||||||
|
Image *i;
|
||||||
|
Channel *c1, *c2; /* chan (tuple(char*, int)) */
|
||||||
|
Consreadmesg crm;
|
||||||
|
Mousereadmesg mrm;
|
||||||
|
Stringpair pair;
|
||||||
|
enum { Adata, Agone, Aflush, Aend };
|
||||||
|
Alt alts[Aend+1];
|
||||||
|
|
||||||
|
w = x->f->w;
|
||||||
|
if(w != nil && w->deleted){
|
||||||
|
filsysrespond(x->fs, x, &fc, Edeleted);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qid = FILE(x->f->qid);
|
||||||
|
off = x->offset;
|
||||||
|
cnt = x->count;
|
||||||
|
switch(qid){
|
||||||
|
case Qwctl:
|
||||||
|
if(w == nil){
|
||||||
|
if(off >= 6*12){
|
||||||
|
filsysrespond(x->fs, x, &fc, Etooshort);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
n = sprint(buf, "%11d %11d %11d %11d nowindow nowindow ",
|
||||||
|
screen->r.min.x, screen->r.min.y, screen->r.max.x, screen->r.max.y);
|
||||||
|
t = estrdup(buf);
|
||||||
|
goto Text;
|
||||||
|
}
|
||||||
|
if(cnt < 4*12){
|
||||||
|
filsysrespond(x->fs, x, &fc, Etooshort);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alts[Adata].c = w->wctlread;
|
||||||
|
goto Consmesg;
|
||||||
|
|
||||||
|
case Qkbd:
|
||||||
|
alts[Adata].c = w->kbdread;
|
||||||
|
goto Consmesg;
|
||||||
|
|
||||||
|
case Qcons:
|
||||||
|
alts[Adata].c = w->consread;
|
||||||
|
|
||||||
|
Consmesg:
|
||||||
|
alts[Adata].v = &crm;
|
||||||
|
alts[Adata].op = CHANRCV;
|
||||||
|
alts[Agone].c = w->gone;
|
||||||
|
alts[Agone].v = nil;
|
||||||
|
alts[Agone].op = CHANRCV;
|
||||||
|
alts[Aflush].c = x->flushc;
|
||||||
|
alts[Aflush].v = nil;
|
||||||
|
alts[Aflush].op = CHANRCV;
|
||||||
|
alts[Aend].op = CHANEND;
|
||||||
|
|
||||||
|
switch(alt(alts)){
|
||||||
|
case Adata:
|
||||||
|
break;
|
||||||
|
case Agone:
|
||||||
|
filsysrespond(x->fs, x, &fc, Edeleted);
|
||||||
|
return;
|
||||||
|
case Aflush:
|
||||||
|
filsyscancel(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c1 = crm.c1;
|
||||||
|
c2 = crm.c2;
|
||||||
|
t = emalloc(cnt+UTFmax+1); /* room to unpack partial rune plus */
|
||||||
|
pair.s = t;
|
||||||
|
pair.ns = cnt;
|
||||||
|
send(c1, &pair);
|
||||||
|
recv(c2, &pair);
|
||||||
|
fc.data = pair.s;
|
||||||
|
fc.count = min(cnt, pair.ns);
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
free(t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qtap:
|
||||||
|
assert(totap != nil);
|
||||||
|
alts[Adata].c = totap;
|
||||||
|
alts[Adata].v = &t;
|
||||||
|
alts[Adata].op = CHANRCV;
|
||||||
|
if(w != nil){
|
||||||
|
alts[Agone].c = w->gone;
|
||||||
|
alts[Agone].v = nil;
|
||||||
|
alts[Agone].op = CHANRCV;
|
||||||
|
} else
|
||||||
|
alts[Agone].op = CHANNOP;
|
||||||
|
alts[Aflush].c = x->flushc;
|
||||||
|
alts[Aflush].v = nil;
|
||||||
|
alts[Aflush].op = CHANRCV;
|
||||||
|
alts[Aend].op = CHANEND;
|
||||||
|
|
||||||
|
switch(alt(alts)){
|
||||||
|
case Adata:
|
||||||
|
break;
|
||||||
|
case Agone:
|
||||||
|
filsysrespond(x->fs, x, &fc, Edeleted);
|
||||||
|
return;
|
||||||
|
case Aflush:
|
||||||
|
filsyscancel(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fc.data = t;
|
||||||
|
/* kbdproc ensures we're only dealing with one message */
|
||||||
|
fc.count = strlen(t)+1;
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
free(t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qlabel:
|
||||||
|
n = strlen(w->label);
|
||||||
|
if(off > n)
|
||||||
|
off = n;
|
||||||
|
if(off+cnt > n)
|
||||||
|
cnt = n-off;
|
||||||
|
fc.data = w->label+off;
|
||||||
|
fc.count = cnt;
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qmouse:
|
||||||
|
alts[Adata].c = w->mouseread;
|
||||||
|
alts[Adata].v = &mrm;
|
||||||
|
alts[Adata].op = CHANRCV;
|
||||||
|
alts[Agone].c = w->gone;
|
||||||
|
alts[Agone].v = nil;
|
||||||
|
alts[Agone].op = CHANRCV;
|
||||||
|
alts[Aflush].c = x->flushc;
|
||||||
|
alts[Aflush].v = nil;
|
||||||
|
alts[Aflush].op = CHANRCV;
|
||||||
|
alts[Aend].op = CHANEND;
|
||||||
|
|
||||||
|
switch(alt(alts)){
|
||||||
|
case Adata:
|
||||||
|
break;
|
||||||
|
case Agone:
|
||||||
|
filsysrespond(x->fs, x, &fc, Edeleted);
|
||||||
|
return;
|
||||||
|
case Aflush:
|
||||||
|
filsyscancel(x);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recv(mrm.cm, &ms);
|
||||||
|
c = 'm';
|
||||||
|
if(w->resized)
|
||||||
|
c = 'r';
|
||||||
|
n = sprint(buf, "%c%11d %11d %11d %11ld ", c, ms.xy.x, ms.xy.y, ms.buttons, ms.msec);
|
||||||
|
w->resized = 0;
|
||||||
|
fc.data = buf;
|
||||||
|
fc.count = min(n, cnt);
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qcursor:
|
||||||
|
filsysrespond(x->fs, x, &fc, "cursor read not implemented");
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* The algorithm for snarf and text is expensive but easy and rarely used */
|
||||||
|
case Qsnarf:
|
||||||
|
getsnarf();
|
||||||
|
if(nsnarf)
|
||||||
|
t = runetobyte(snarf, nsnarf, &n);
|
||||||
|
else {
|
||||||
|
t = nil;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
goto Text;
|
||||||
|
|
||||||
|
case Qtext:
|
||||||
|
t = wcontents(w, &n);
|
||||||
|
goto Text;
|
||||||
|
|
||||||
|
Text:
|
||||||
|
if(off > n){
|
||||||
|
off = n;
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
if(off+cnt > n)
|
||||||
|
cnt = n-off;
|
||||||
|
fc.data = t+off;
|
||||||
|
fc.count = cnt;
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
free(t);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qwdir:
|
||||||
|
t = estrdup(w->dir);
|
||||||
|
n = strlen(t);
|
||||||
|
goto Text;
|
||||||
|
|
||||||
|
case Qwinid:
|
||||||
|
n = sprint(buf, "%11d ", w->id);
|
||||||
|
t = estrdup(buf);
|
||||||
|
goto Text;
|
||||||
|
|
||||||
|
|
||||||
|
case Qwinname:
|
||||||
|
n = strlen(w->name);
|
||||||
|
if(n == 0){
|
||||||
|
filsysrespond(x->fs, x, &fc, "window has no name");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t = estrdup(w->name);
|
||||||
|
w->winnameread = TRUE;
|
||||||
|
goto Text;
|
||||||
|
|
||||||
|
case Qwindow:
|
||||||
|
i = w->i;
|
||||||
|
if(i == nil){
|
||||||
|
filsysrespond(x->fs, x, &fc, Enowindow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r = i->r;
|
||||||
|
goto caseImage;
|
||||||
|
|
||||||
|
case Qscreen:
|
||||||
|
i = screen;
|
||||||
|
r = screen->r;
|
||||||
|
|
||||||
|
caseImage:
|
||||||
|
if(off < 5*12){
|
||||||
|
n = sprint(buf, "%11s %11d %11d %11d %11d ",
|
||||||
|
chantostr(cbuf, i->chan),
|
||||||
|
r.min.x, r.min.y, r.max.x, r.max.y);
|
||||||
|
t = estrdup(buf);
|
||||||
|
goto Text;
|
||||||
|
}
|
||||||
|
off -= 5*12;
|
||||||
|
n = -1;
|
||||||
|
t = malloc(cnt);
|
||||||
|
if(t){
|
||||||
|
fc.data = t;
|
||||||
|
n = readwindow(i, t, r, off, cnt); /* careful; fc.count is unsigned */
|
||||||
|
}
|
||||||
|
if(n < 0){
|
||||||
|
buf[0] = 0;
|
||||||
|
errstr(buf, sizeof buf);
|
||||||
|
filsysrespond(x->fs, x, &fc, buf);
|
||||||
|
}else{
|
||||||
|
fc.count = n;
|
||||||
|
filsysrespond(x->fs, x, &fc, nil);
|
||||||
|
}
|
||||||
|
free(t);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprint(2, "unknown qid %d in read\n", qid);
|
||||||
|
snprint(buf, sizeof(buf), "unknown qid in read");
|
||||||
|
filsysrespond(x->fs, x, &fc, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue