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