devdraw: more cleanup, clearer locking
This commit is contained in:
parent
b1a086dee9
commit
41547af3f6
8 changed files with 331 additions and 315 deletions
|
|
@ -14,14 +14,12 @@
|
||||||
#include <drawfcall.h>
|
#include <drawfcall.h>
|
||||||
#include "devdraw.h"
|
#include "devdraw.h"
|
||||||
|
|
||||||
static Draw sdraw;
|
|
||||||
Client *client0;
|
|
||||||
static int drawuninstall(Client*, int);
|
static int drawuninstall(Client*, int);
|
||||||
static Memimage* drawinstall(Client*, int, Memimage*, DScreen*);
|
static Memimage* drawinstall(Client*, int, Memimage*, DScreen*);
|
||||||
static void drawfreedimage(Client*, DImage*);
|
static void drawfreedimage(Client*, DImage*);
|
||||||
|
|
||||||
void
|
void
|
||||||
_initdisplaymemimage(Client *c, Memimage *m)
|
draw_initdisplaymemimage(Client *c, Memimage *m)
|
||||||
{
|
{
|
||||||
c->screenimage = m;
|
c->screenimage = m;
|
||||||
m->screenref = 1;
|
m->screenref = 1;
|
||||||
|
|
@ -30,10 +28,10 @@ _initdisplaymemimage(Client *c, Memimage *m)
|
||||||
c->op = SoverD;
|
c->op = SoverD;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _drawreplacescreen replaces c's screen image with m.
|
// gfx_replacescreenimage replaces c's screen image with m.
|
||||||
// It is called by the host driver on the main host thread.
|
// It is called by the host driver on the main host thread.
|
||||||
void
|
void
|
||||||
_drawreplacescreenimage(Client *c, Memimage *m)
|
gfx_replacescreenimage(Client *c, Memimage *m)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Replace the screen image because the screen
|
* Replace the screen image because the screen
|
||||||
|
|
@ -49,21 +47,21 @@ _drawreplacescreenimage(Client *c, Memimage *m)
|
||||||
*/
|
*/
|
||||||
Memimage *om;
|
Memimage *om;
|
||||||
|
|
||||||
qlock(&c->inputlk);
|
qlock(&c->drawlk);
|
||||||
qlock(&sdraw.lk);
|
|
||||||
om = c->screenimage;
|
om = c->screenimage;
|
||||||
c->screenimage = m;
|
c->screenimage = m;
|
||||||
m->screenref = 1;
|
m->screenref = 1;
|
||||||
c->mouse.resized = 1;
|
|
||||||
if(om && --om->screenref == 0){
|
if(om && --om->screenref == 0){
|
||||||
_freememimage(om);
|
_freememimage(om);
|
||||||
}
|
}
|
||||||
qunlock(&sdraw.lk);
|
qunlock(&c->drawlk);
|
||||||
qunlock(&c->inputlk);
|
|
||||||
|
qlock(&c->eventlk);
|
||||||
|
c->mouse.resized = 1;
|
||||||
|
qunlock(&c->eventlk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawrefreshscreen(DImage *l, Client *client)
|
drawrefreshscreen(DImage *l, Client *client)
|
||||||
{
|
{
|
||||||
while(l != nil && l->dscreen == nil)
|
while(l != nil && l->dscreen == nil)
|
||||||
|
|
@ -72,8 +70,7 @@ drawrefreshscreen(DImage *l, Client *client)
|
||||||
l->dscreen->owner->refreshme = 1;
|
l->dscreen->owner->refreshme = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawrefresh(Memimage *m, Rectangle r, void *v)
|
drawrefresh(Memimage *m, Rectangle r, void *v)
|
||||||
{
|
{
|
||||||
Refx *x;
|
Refx *x;
|
||||||
|
|
@ -106,7 +103,7 @@ static void
|
||||||
addflush(Client *c, Rectangle r)
|
addflush(Client *c, Rectangle r)
|
||||||
{
|
{
|
||||||
int abb, ar, anbb;
|
int abb, ar, anbb;
|
||||||
Rectangle nbb;
|
Rectangle nbb, fr;
|
||||||
|
|
||||||
if(/*sdraw.softscreen==0 ||*/ !rectclip(&r, c->screenimage->r))
|
if(/*sdraw.softscreen==0 ||*/ !rectclip(&r, c->screenimage->r))
|
||||||
return;
|
return;
|
||||||
|
|
@ -140,14 +137,20 @@ addflush(Client *c, Rectangle r)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* emit current state */
|
/* emit current state */
|
||||||
if(c->flushrect.min.x < c->flushrect.max.x)
|
fr = c->flushrect;
|
||||||
rpc_flushmemscreen(c, c->flushrect);
|
|
||||||
c->flushrect = r;
|
c->flushrect = r;
|
||||||
c->waste = 0;
|
c->waste = 0;
|
||||||
|
if(fr.min.x < fr.max.x) {
|
||||||
|
// Unlock drawlk because rpc_flush may want to run on gfx thread,
|
||||||
|
// and gfx thread might be blocked on drawlk trying to install a new screen
|
||||||
|
// during a resize.
|
||||||
|
qunlock(&c->drawlk);
|
||||||
|
rpc_flush(c, fr);
|
||||||
|
qlock(&c->drawlk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
|
dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
|
||||||
{
|
{
|
||||||
Memlayer *l;
|
Memlayer *l;
|
||||||
|
|
@ -173,17 +176,24 @@ dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
|
||||||
addflush(c, r);
|
addflush(c, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawflush(Client *c)
|
drawflush(Client *c)
|
||||||
{
|
{
|
||||||
if(c->flushrect.min.x < c->flushrect.max.x)
|
Rectangle r;
|
||||||
rpc_flushmemscreen(c, c->flushrect);
|
|
||||||
|
r = c->flushrect;
|
||||||
c->flushrect = Rect(10000, 10000, -10000, -10000);
|
c->flushrect = Rect(10000, 10000, -10000, -10000);
|
||||||
|
if(r.min.x < r.max.x) {
|
||||||
|
// Unlock drawlk because rpc_flush may want to run on gfx thread,
|
||||||
|
// and gfx thread might be blocked on drawlk trying to install a new screen
|
||||||
|
// during a resize.
|
||||||
|
qunlock(&c->drawlk);
|
||||||
|
rpc_flush(c, r);
|
||||||
|
qlock(&c->drawlk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int
|
||||||
int
|
|
||||||
drawcmp(char *a, char *b, int n)
|
drawcmp(char *a, char *b, int n)
|
||||||
{
|
{
|
||||||
if(strlen(a) != n)
|
if(strlen(a) != n)
|
||||||
|
|
@ -191,8 +201,7 @@ drawcmp(char *a, char *b, int n)
|
||||||
return memcmp(a, b, n);
|
return memcmp(a, b, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static DName*
|
||||||
DName*
|
|
||||||
drawlookupname(Client *client, int n, char *str)
|
drawlookupname(Client *client, int n, char *str)
|
||||||
{
|
{
|
||||||
DName *name, *ename;
|
DName *name, *ename;
|
||||||
|
|
@ -205,8 +214,7 @@ drawlookupname(Client *client, int n, char *str)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int
|
||||||
int
|
|
||||||
drawgoodname(Client *client, DImage *d)
|
drawgoodname(Client *client, DImage *d)
|
||||||
{
|
{
|
||||||
DName *n;
|
DName *n;
|
||||||
|
|
@ -224,8 +232,7 @@ drawgoodname(Client *client, DImage *d)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static DImage*
|
||||||
DImage*
|
|
||||||
drawlookup(Client *client, int id, int checkname)
|
drawlookup(Client *client, int id, int checkname)
|
||||||
{
|
{
|
||||||
DImage *d;
|
DImage *d;
|
||||||
|
|
@ -246,8 +253,7 @@ drawlookup(Client *client, int id, int checkname)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static DScreen*
|
||||||
DScreen*
|
|
||||||
drawlookupdscreen(Client *c, int id)
|
drawlookupdscreen(Client *c, int id)
|
||||||
{
|
{
|
||||||
DScreen *s;
|
DScreen *s;
|
||||||
|
|
@ -261,8 +267,7 @@ drawlookupdscreen(Client *c, int id)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static DScreen*
|
||||||
DScreen*
|
|
||||||
drawlookupscreen(Client *client, int id, CScreen **cs)
|
drawlookupscreen(Client *client, int id, CScreen **cs)
|
||||||
{
|
{
|
||||||
CScreen *s;
|
CScreen *s;
|
||||||
|
|
@ -279,8 +284,7 @@ drawlookupscreen(Client *client, int id, CScreen **cs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Memimage*
|
||||||
Memimage*
|
|
||||||
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
|
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
|
||||||
{
|
{
|
||||||
DImage *d;
|
DImage *d;
|
||||||
|
|
@ -304,8 +308,7 @@ drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Memscreen*
|
||||||
Memscreen*
|
|
||||||
drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
|
drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
|
||||||
{
|
{
|
||||||
Memscreen *s;
|
Memscreen *s;
|
||||||
|
|
@ -358,8 +361,7 @@ drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *df
|
||||||
return d->screen;
|
return d->screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawdelname(Client *client, DName *name)
|
drawdelname(Client *client, DName *name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -369,8 +371,7 @@ drawdelname(Client *client, DName *name)
|
||||||
client->nname--;
|
client->nname--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawfreedscreen(Client *client, DScreen *this)
|
drawfreedscreen(Client *client, DScreen *this)
|
||||||
{
|
{
|
||||||
DScreen *ds, *next;
|
DScreen *ds, *next;
|
||||||
|
|
@ -406,8 +407,7 @@ drawfreedscreen(Client *client, DScreen *this)
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawfreedimage(Client *client, DImage *dimage)
|
drawfreedimage(Client *client, DImage *dimage)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -456,8 +456,7 @@ drawfreedimage(Client *client, DImage *dimage)
|
||||||
free(dimage);
|
free(dimage);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawuninstallscreen(Client *client, CScreen *this)
|
drawuninstallscreen(Client *client, CScreen *this)
|
||||||
{
|
{
|
||||||
CScreen *cs, *next;
|
CScreen *cs, *next;
|
||||||
|
|
@ -480,8 +479,7 @@ drawuninstallscreen(Client *client, CScreen *this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int
|
||||||
int
|
|
||||||
drawuninstall(Client *client, int id)
|
drawuninstall(Client *client, int id)
|
||||||
{
|
{
|
||||||
DImage *d, **l;
|
DImage *d, **l;
|
||||||
|
|
@ -496,8 +494,7 @@ drawuninstall(Client *client, int id)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static int
|
||||||
int
|
|
||||||
drawaddname(Client *client, DImage *di, int n, char *str, char **err)
|
drawaddname(Client *client, DImage *di, int n, char *str, char **err)
|
||||||
{
|
{
|
||||||
DName *name, *ename, *new, *t;
|
DName *name, *ename, *new, *t;
|
||||||
|
|
@ -541,8 +538,7 @@ drawclientop(Client *cl)
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Memimage*
|
||||||
Memimage*
|
|
||||||
drawimage(Client *client, uchar *a)
|
drawimage(Client *client, uchar *a)
|
||||||
{
|
{
|
||||||
DImage *d;
|
DImage *d;
|
||||||
|
|
@ -553,8 +549,7 @@ drawimage(Client *client, uchar *a)
|
||||||
return d->image;
|
return d->image;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawrectangle(Rectangle *r, uchar *a)
|
drawrectangle(Rectangle *r, uchar *a)
|
||||||
{
|
{
|
||||||
r->min.x = BGLONG(a+0*4);
|
r->min.x = BGLONG(a+0*4);
|
||||||
|
|
@ -563,16 +558,14 @@ drawrectangle(Rectangle *r, uchar *a)
|
||||||
r->max.y = BGLONG(a+3*4);
|
r->max.y = BGLONG(a+3*4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static void
|
||||||
void
|
|
||||||
drawpoint(Point *p, uchar *a)
|
drawpoint(Point *p, uchar *a)
|
||||||
{
|
{
|
||||||
p->x = BGLONG(a+0*4);
|
p->x = BGLONG(a+0*4);
|
||||||
p->y = BGLONG(a+1*4);
|
p->y = BGLONG(a+1*4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static Point
|
||||||
Point
|
|
||||||
drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
|
drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
|
||||||
{
|
{
|
||||||
FChar *fc;
|
FChar *fc;
|
||||||
|
|
@ -592,8 +585,7 @@ drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int ind
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static uchar*
|
||||||
uchar*
|
|
||||||
drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
|
drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
|
||||||
{
|
{
|
||||||
int b, x;
|
int b, x;
|
||||||
|
|
@ -619,9 +611,9 @@ drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_drawmsgread(Client *cl, void *a, int n)
|
draw_dataread(Client *cl, void *a, int n)
|
||||||
{
|
{
|
||||||
qlock(&sdraw.lk);
|
qlock(&cl->drawlk);
|
||||||
if(cl->readdata == nil){
|
if(cl->readdata == nil){
|
||||||
werrstr("no draw data");
|
werrstr("no draw data");
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -634,16 +626,16 @@ _drawmsgread(Client *cl, void *a, int n)
|
||||||
memmove(a, cl->readdata, cl->nreaddata);
|
memmove(a, cl->readdata, cl->nreaddata);
|
||||||
free(cl->readdata);
|
free(cl->readdata);
|
||||||
cl->readdata = nil;
|
cl->readdata = nil;
|
||||||
qunlock(&sdraw.lk);
|
qunlock(&cl->drawlk);
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
qunlock(&sdraw.lk);
|
qunlock(&cl->drawlk);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_drawmsgwrite(Client *client, void *v, int n)
|
draw_datawrite(Client *client, void *v, int n)
|
||||||
{
|
{
|
||||||
char cbuf[40], *err, ibuf[12*12+1], *s;
|
char cbuf[40], *err, ibuf[12*12+1], *s;
|
||||||
int c, ci, doflush, dstid, e0, e1, esize, j, m;
|
int c, ci, doflush, dstid, e0, e1, esize, j, m;
|
||||||
|
|
@ -663,7 +655,7 @@ _drawmsgwrite(Client *client, void *v, int n)
|
||||||
Refreshfn reffn;
|
Refreshfn reffn;
|
||||||
Refx *refx;
|
Refx *refx;
|
||||||
|
|
||||||
qlock(&sdraw.lk);
|
qlock(&client->drawlk);
|
||||||
a = v;
|
a = v;
|
||||||
m = 0;
|
m = 0;
|
||||||
oldn = n;
|
oldn = n;
|
||||||
|
|
@ -1436,7 +1428,7 @@ _drawmsgwrite(Client *client, void *v, int n)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qunlock(&sdraw.lk);
|
qunlock(&client->drawlk);
|
||||||
return oldn - n;
|
return oldn - n;
|
||||||
|
|
||||||
Enodrawimage:
|
Enodrawimage:
|
||||||
|
|
@ -1506,6 +1498,6 @@ Ebadarg:
|
||||||
|
|
||||||
error:
|
error:
|
||||||
werrstr("%s", err);
|
werrstr("%s", err);
|
||||||
qunlock(&sdraw.lk);
|
qunlock(&client->drawlk);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ typedef struct Mousebuf Mousebuf;
|
||||||
typedef struct Tagbuf Tagbuf;
|
typedef struct Tagbuf Tagbuf;
|
||||||
|
|
||||||
typedef struct Client Client;
|
typedef struct Client Client;
|
||||||
typedef struct Draw Draw;
|
|
||||||
typedef struct DImage DImage;
|
typedef struct DImage DImage;
|
||||||
typedef struct DScreen DScreen;
|
typedef struct DScreen DScreen;
|
||||||
typedef struct CScreen CScreen;
|
typedef struct CScreen CScreen;
|
||||||
|
|
@ -16,11 +15,6 @@ typedef struct Refresh Refresh;
|
||||||
typedef struct Refx Refx;
|
typedef struct Refx Refx;
|
||||||
typedef struct DName DName;
|
typedef struct DName DName;
|
||||||
|
|
||||||
struct Draw
|
|
||||||
{
|
|
||||||
QLock lk;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Kbdbuf
|
struct Kbdbuf
|
||||||
{
|
{
|
||||||
Rune r[256];
|
Rune r[256];
|
||||||
|
|
@ -51,6 +45,19 @@ struct Tagbuf
|
||||||
|
|
||||||
struct Client
|
struct Client
|
||||||
{
|
{
|
||||||
|
int rfd;
|
||||||
|
|
||||||
|
// wfdlk protects writes to wfd, which can be issued from either
|
||||||
|
// the RPC thread or the graphics thread.
|
||||||
|
QLock wfdlk;
|
||||||
|
int wfd;
|
||||||
|
uchar* mbuf;
|
||||||
|
int nmbuf;
|
||||||
|
|
||||||
|
// drawlk protects the draw data structures.
|
||||||
|
// It can be acquired by an RPC thread or a graphics thread
|
||||||
|
// but must not be held on one thread while waiting for the other.
|
||||||
|
QLock drawlk;
|
||||||
/*Ref r;*/
|
/*Ref r;*/
|
||||||
DImage* dimage[NHASH];
|
DImage* dimage[NHASH];
|
||||||
CScreen* cscreen;
|
CScreen* cscreen;
|
||||||
|
|
@ -64,7 +71,6 @@ struct Client
|
||||||
int refreshme;
|
int refreshme;
|
||||||
int infoid;
|
int infoid;
|
||||||
int op;
|
int op;
|
||||||
|
|
||||||
int displaydpi;
|
int displaydpi;
|
||||||
int forcedpi;
|
int forcedpi;
|
||||||
int waste;
|
int waste;
|
||||||
|
|
@ -75,11 +81,11 @@ struct Client
|
||||||
DName* name;
|
DName* name;
|
||||||
int namevers;
|
int namevers;
|
||||||
|
|
||||||
int rfd;
|
// Only accessed/modified by the graphics thread.
|
||||||
int wfd;
|
|
||||||
const void* view;
|
const void* view;
|
||||||
|
|
||||||
QLock inputlk;
|
// eventlk protects the keyboard and mouse events.
|
||||||
|
QLock eventlk;
|
||||||
Kbdbuf kbd;
|
Kbdbuf kbd;
|
||||||
Mousebuf mouse;
|
Mousebuf mouse;
|
||||||
Tagbuf kbdtags;
|
Tagbuf kbdtags;
|
||||||
|
|
@ -157,30 +163,59 @@ struct DScreen
|
||||||
DScreen* next;
|
DScreen* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
int _drawmsgread(Client*, void*, int);
|
// For the most part, the graphics driver-specific code in files
|
||||||
int _drawmsgwrite(Client*, void*, int);
|
// like mac-screen.m runs in the graphics library's main thread,
|
||||||
void _initdisplaymemimage(Client*, Memimage*);
|
// while the RPC service code in srv.c runs on the RPC service thread.
|
||||||
void _drawreplacescreenimage(Client*, Memimage*);
|
// The exceptions in each file, which are called by the other,
|
||||||
|
// are marked with special prefixes: gfx_* indicates code that
|
||||||
int _latin1(Rune*, int);
|
// is in srv.c but nonetheless runs on the main graphics thread,
|
||||||
int parsewinsize(char*, Rectangle*, int*);
|
// while rpc_* indicates code that is in, say, mac-screen.m but
|
||||||
int mouseswap(int);
|
// nonetheless runs on the RPC service thread.
|
||||||
|
//
|
||||||
|
// The gfx_* and rpc_* calls typically synchronize with the other
|
||||||
|
// code in the file by acquiring a lock (or running a callback on the
|
||||||
|
// target thread, which amounts to the same thing).
|
||||||
|
// To avoid deadlock, callers of those routines must not hold any locks.
|
||||||
|
|
||||||
|
// gfx_* routines are called on the graphics thread,
|
||||||
|
// invoked from graphics driver callbacks to do RPC work.
|
||||||
|
// No locks are held on entry.
|
||||||
void gfx_abortcompose(Client*);
|
void gfx_abortcompose(Client*);
|
||||||
void gfx_keystroke(Client*, int);
|
void gfx_keystroke(Client*, int);
|
||||||
|
void gfx_main(void);
|
||||||
void gfx_mousetrack(Client*, int, int, int, uint);
|
void gfx_mousetrack(Client*, int, int, int, uint);
|
||||||
|
void gfx_replacescreenimage(Client*, Memimage*);
|
||||||
|
void gfx_started(void);
|
||||||
|
|
||||||
void rpc_setmouse(Client*, Point);
|
// rpc_* routines are called on the RPC thread,
|
||||||
void rpc_setcursor(Client*, Cursor*, Cursor2*);
|
// invoked by the RPC server code to do graphics work.
|
||||||
void rpc_setlabel(Client*, char*);
|
// No locks are held on entry.
|
||||||
void rpc_resizeimg(Client*);
|
Memimage *rpc_attach(Client*, char*, char*);
|
||||||
void rpc_resizewindow(Client*, Rectangle);
|
|
||||||
void rpc_topwin(Client*);
|
|
||||||
char* rpc_getsnarf(void);
|
char* rpc_getsnarf(void);
|
||||||
void rpc_putsnarf(char*);
|
void rpc_putsnarf(char*);
|
||||||
Memimage *rpc_attachscreen(Client*, char*, char*);
|
void rpc_resizeimg(Client*);
|
||||||
void rpc_flushmemscreen(Client*, Rectangle);
|
void rpc_resizewindow(Client*, Rectangle);
|
||||||
|
void rpc_serve(Client*);
|
||||||
|
void rpc_setcursor(Client*, Cursor*, Cursor2*);
|
||||||
|
void rpc_setlabel(Client*, char*);
|
||||||
|
void rpc_setmouse(Client*, Point);
|
||||||
|
void rpc_shutdown(void);
|
||||||
|
void rpc_topwin(Client*);
|
||||||
|
void rpc_main(void);
|
||||||
|
|
||||||
extern Client *client0;
|
// TODO: rpc_flush is called from draw_datawrite,
|
||||||
|
// which holds c->drawlk. Is this OK?
|
||||||
|
void rpc_flush(Client*, Rectangle);
|
||||||
|
|
||||||
|
// draw* routines are called on the RPC thread,
|
||||||
|
// invoked by the RPC server to do pixel pushing.
|
||||||
|
// c->drawlk is held on entry.
|
||||||
|
int draw_dataread(Client*, void*, int);
|
||||||
|
int draw_datawrite(Client*, void*, int);
|
||||||
|
void draw_initdisplaymemimage(Client*, Memimage*);
|
||||||
|
|
||||||
|
// utility routines
|
||||||
|
int latin1(Rune*, int);
|
||||||
|
int mouseswap(int);
|
||||||
|
int parsewinsize(char*, Rectangle*, int*);
|
||||||
|
|
||||||
void servep9p(Client*);
|
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ unicode(Rune *k)
|
||||||
* is minus the required n.
|
* is minus the required n.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
_latin1(Rune *k, int n)
|
latin1(Rune *k, int n)
|
||||||
{
|
{
|
||||||
struct cvlist *l;
|
struct cvlist *l;
|
||||||
int c;
|
int c;
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,6 @@ static void setprocname(const char*);
|
||||||
static uint keycvt(uint);
|
static uint keycvt(uint);
|
||||||
static uint msec(void);
|
static uint msec(void);
|
||||||
|
|
||||||
void
|
|
||||||
usage(void)
|
|
||||||
{
|
|
||||||
fprint(2, "usage: devdraw (don't run directly)\n");
|
|
||||||
threadexitsall("usage");
|
|
||||||
}
|
|
||||||
|
|
||||||
@class DrawView;
|
@class DrawView;
|
||||||
@class DrawLayer;
|
@class DrawLayer;
|
||||||
|
|
||||||
|
|
@ -49,43 +42,9 @@ usage(void)
|
||||||
|
|
||||||
static AppDelegate *myApp = NULL;
|
static AppDelegate *myApp = NULL;
|
||||||
|
|
||||||
|
|
||||||
static QLock snarfl;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
threadmain(int argc, char **argv)
|
gfx_main(void)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* Move the protocol off stdin/stdout so that
|
|
||||||
* any inadvertent prints don't screw things up.
|
|
||||||
*/
|
|
||||||
dup(0,3);
|
|
||||||
dup(1,4);
|
|
||||||
close(0);
|
|
||||||
close(1);
|
|
||||||
open("/dev/null", OREAD);
|
|
||||||
open("/dev/null", OWRITE);
|
|
||||||
|
|
||||||
ARGBEGIN{
|
|
||||||
case 'D': /* for good ps -a listings */
|
|
||||||
break;
|
|
||||||
case 'f': /* fall through for backward compatibility */
|
|
||||||
case 'g':
|
|
||||||
case 'b':
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
}ARGEND
|
|
||||||
|
|
||||||
client0 = mallocz(sizeof(Client), 1);
|
|
||||||
if(client0 == nil){
|
|
||||||
fprint(2, "initdraw: allocating client0: out of memory");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
client0->displaydpi = 100;
|
|
||||||
client0->rfd = 3;
|
|
||||||
client0->wfd = 4;
|
|
||||||
|
|
||||||
setprocname(argv0);
|
setprocname(argv0);
|
||||||
|
|
||||||
@autoreleasepool{
|
@autoreleasepool{
|
||||||
|
|
@ -97,12 +56,10 @@ threadmain(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
callservep9p(void *v)
|
|
||||||
{
|
|
||||||
USED(v);
|
|
||||||
|
|
||||||
servep9p(client0);
|
void
|
||||||
|
rpc_shutdown(void)
|
||||||
|
{
|
||||||
[NSApp terminate:myApp];
|
[NSApp terminate:myApp];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +86,7 @@ callservep9p(void *v)
|
||||||
[NSApp setApplicationIconImage:i];
|
[NSApp setApplicationIconImage:i];
|
||||||
[[NSApp dockTile] display];
|
[[NSApp dockTile] display];
|
||||||
|
|
||||||
proccreate(callservep9p, nil, 0);
|
gfx_started();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSApplicationPresentationOptions)window:(id)arg
|
- (NSApplicationPresentationOptions)window:(id)arg
|
||||||
|
|
@ -242,10 +199,10 @@ callservep9p(void *v)
|
||||||
- (BOOL)isFlipped { return YES; }
|
- (BOOL)isFlipped { return YES; }
|
||||||
- (BOOL)acceptsFirstResponder { return YES; }
|
- (BOOL)acceptsFirstResponder { return YES; }
|
||||||
|
|
||||||
// rpc_attachscreen allocates a new screen window with the given label and size
|
// rpc_attach allocates a new screen window with the given label and size
|
||||||
// and attaches it to client c (by setting c->view).
|
// and attaches it to client c (by setting c->view).
|
||||||
Memimage*
|
Memimage*
|
||||||
rpc_attachscreen(Client *c, char *label, char *winsize)
|
rpc_attach(Client *c, char *label, char *winsize)
|
||||||
{
|
{
|
||||||
LOG(@"attachscreen(%s, %s)", label, winsize);
|
LOG(@"attachscreen(%s, %s)", label, winsize);
|
||||||
|
|
||||||
|
|
@ -468,7 +425,7 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)initimg {
|
- (void)initimg {
|
||||||
@autoreleasepool{
|
@autoreleasepool {
|
||||||
CGFloat scale;
|
CGFloat scale;
|
||||||
NSSize size;
|
NSSize size;
|
||||||
MTLTextureDescriptor *textureDesc;
|
MTLTextureDescriptor *textureDesc;
|
||||||
|
|
@ -504,35 +461,37 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
|
||||||
// That's not quite right but it's close to correct.
|
// That's not quite right but it's close to correct.
|
||||||
// https://en.wikipedia.org/wiki/Retina_display#Models
|
// https://en.wikipedia.org/wiki/Retina_display#Models
|
||||||
self.client->displaydpi = scale * 110;
|
self.client->displaydpi = scale * 110;
|
||||||
}
|
}
|
||||||
LOG(@"initimg return");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// rpc_flushmemscreen flushes changes to view.img's rectangle r
|
// rpc_flush flushes changes to view.img's rectangle r
|
||||||
// to the on-screen window, making them visible.
|
// to the on-screen window, making them visible.
|
||||||
// Called from an RPC thread with no client lock held.
|
// Called from an RPC thread with no client lock held.
|
||||||
void
|
void
|
||||||
rpc_flushmemscreen(Client *client, Rectangle r)
|
rpc_flush(Client *client, Rectangle r)
|
||||||
{
|
{
|
||||||
DrawView *view = (__bridge DrawView*)client->view;
|
DrawView *view = (__bridge DrawView*)client->view;
|
||||||
dispatch_async(dispatch_get_main_queue(), ^(void){
|
dispatch_async(dispatch_get_main_queue(), ^(void){
|
||||||
[view flushmemscreen:r];
|
[view flush:r];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)flushmemscreen:(Rectangle)r {
|
- (void)flush:(Rectangle)r {
|
||||||
LOG(@"flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r));
|
|
||||||
if(!rectinrect(r, Rect(0, 0, self.dlayer.texture.width, self.dlayer.texture.height))){
|
|
||||||
LOG(@"Rectangle is out of bounds, return.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
@autoreleasepool{
|
@autoreleasepool{
|
||||||
|
if(!rectclip(&r, Rect(0, 0, self.dlayer.texture.width, self.dlayer.texture.height)) || !rectclip(&r, self.img->r))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// self.client->drawlk protects the pixel data in self.img.
|
||||||
|
// In addition to avoiding a technical data race,
|
||||||
|
// the lock avoids drawing partial updates, which makes
|
||||||
|
// animations like sweeping windows much less flickery.
|
||||||
|
qlock(&self.client->drawlk);
|
||||||
[self.dlayer.texture
|
[self.dlayer.texture
|
||||||
replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
|
replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
|
||||||
mipmapLevel:0
|
mipmapLevel:0
|
||||||
withBytes:byteaddr(self.img, Pt(r.min.x, r.min.y))
|
withBytes:byteaddr(self.img, Pt(r.min.x, r.min.y))
|
||||||
bytesPerRow:self.img->width*sizeof(u32int)];
|
bytesPerRow:self.img->width*sizeof(u32int)];
|
||||||
|
qunlock(&self.client->drawlk);
|
||||||
|
|
||||||
NSRect nr = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
|
NSRect nr = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
|
||||||
dispatch_time_t time;
|
dispatch_time_t time;
|
||||||
|
|
@ -565,7 +524,7 @@ rpc_resizeimg(Client *c)
|
||||||
|
|
||||||
- (void)resizeimg {
|
- (void)resizeimg {
|
||||||
[self initimg];
|
[self initimg];
|
||||||
_drawreplacescreenimage(self.client, self.img);
|
gfx_replacescreenimage(self.client, self.img);
|
||||||
[self sendmouse:0];
|
[self sendmouse:0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -750,7 +709,7 @@ rpc_setmouse(Client *c, Point p)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)setmouse:(Point)p {
|
- (void)setmouse:(Point)p {
|
||||||
@autoreleasepool{
|
@autoreleasepool{
|
||||||
NSPoint q;
|
NSPoint q;
|
||||||
|
|
||||||
|
|
@ -782,21 +741,10 @@ rpc_setmouse(Client *c, Point p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// conforms to protocol NSTextInputClient
|
// conforms to protocol NSTextInputClient
|
||||||
- (BOOL)hasMarkedText
|
- (BOOL)hasMarkedText { return _markedRange.location != NSNotFound; }
|
||||||
{
|
- (NSRange)markedRange { return _markedRange; }
|
||||||
LOG(@"hasMarkedText");
|
- (NSRange)selectedRange { return _selectedRange; }
|
||||||
return _markedRange.location != NSNotFound;
|
|
||||||
}
|
|
||||||
- (NSRange)markedRange
|
|
||||||
{
|
|
||||||
LOG(@"markedRange");
|
|
||||||
return _markedRange;
|
|
||||||
}
|
|
||||||
- (NSRange)selectedRange
|
|
||||||
{
|
|
||||||
LOG(@"selectedRange");
|
|
||||||
return _selectedRange;
|
|
||||||
}
|
|
||||||
- (void)setMarkedText:(id)string
|
- (void)setMarkedText:(id)string
|
||||||
selectedRange:(NSRange)sRange
|
selectedRange:(NSRange)sRange
|
||||||
replacementRange:(NSRange)rRange
|
replacementRange:(NSRange)rRange
|
||||||
|
|
@ -861,8 +809,8 @@ rpc_setmouse(Client *c, Point p)
|
||||||
_markedRange.location, _markedRange.length,
|
_markedRange.location, _markedRange.length,
|
||||||
_selectedRange.location, _selectedRange.length);
|
_selectedRange.location, _selectedRange.length);
|
||||||
}
|
}
|
||||||
- (void)unmarkText
|
|
||||||
{
|
- (void)unmarkText {
|
||||||
//NSUInteger i;
|
//NSUInteger i;
|
||||||
NSUInteger len;
|
NSUInteger len;
|
||||||
|
|
||||||
|
|
@ -874,12 +822,13 @@ rpc_setmouse(Client *c, Point p)
|
||||||
_markedRange = NSMakeRange(NSNotFound, 0);
|
_markedRange = NSMakeRange(NSNotFound, 0);
|
||||||
_selectedRange = NSMakeRange(0, 0);
|
_selectedRange = NSMakeRange(0, 0);
|
||||||
}
|
}
|
||||||
- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
|
|
||||||
{
|
- (NSArray<NSAttributedStringKey>*)validAttributesForMarkedText {
|
||||||
LOG(@"validAttributesForMarkedText");
|
LOG(@"validAttributesForMarkedText");
|
||||||
return @[];
|
return @[];
|
||||||
}
|
}
|
||||||
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
|
|
||||||
|
- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)r
|
||||||
actualRange:(NSRangePointer)actualRange
|
actualRange:(NSRangePointer)actualRange
|
||||||
{
|
{
|
||||||
NSRange sr;
|
NSRange sr;
|
||||||
|
|
@ -899,9 +848,8 @@ rpc_setmouse(Client *c, Point p)
|
||||||
LOG(@" return %@", s);
|
LOG(@" return %@", s);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
- (void)insertText:(id)s
|
|
||||||
replacementRange:(NSRange)r
|
- (void)insertText:(id)s replacementRange:(NSRange)r {
|
||||||
{
|
|
||||||
NSUInteger i;
|
NSUInteger i;
|
||||||
NSUInteger len;
|
NSUInteger len;
|
||||||
|
|
||||||
|
|
@ -916,22 +864,22 @@ rpc_setmouse(Client *c, Point p)
|
||||||
_markedRange = NSMakeRange(NSNotFound, 0);
|
_markedRange = NSMakeRange(NSNotFound, 0);
|
||||||
_selectedRange = NSMakeRange(0, 0);
|
_selectedRange = NSMakeRange(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger)characterIndexForPoint:(NSPoint)point
|
- (NSUInteger)characterIndexForPoint:(NSPoint)point
|
||||||
{
|
{
|
||||||
LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
|
LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
- (NSRect)firstRectForCharacterRange:(NSRange)r
|
|
||||||
actualRange:(NSRangePointer)actualRange
|
- (NSRect)firstRectForCharacterRange:(NSRange)r actualRange:(NSRangePointer)actualRange {
|
||||||
{
|
|
||||||
LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
|
LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
|
||||||
r.location, r.length, actualRange->location, actualRange->length);
|
r.location, r.length, actualRange->location, actualRange->length);
|
||||||
if(actualRange)
|
if(actualRange)
|
||||||
*actualRange = r;
|
*actualRange = r;
|
||||||
return [[self window] convertRectToScreen:_lastInputRect];
|
return [[self window] convertRectToScreen:_lastInputRect];
|
||||||
}
|
}
|
||||||
- (void)doCommandBySelector:(SEL)s
|
|
||||||
{
|
- (void)doCommandBySelector:(SEL)s {
|
||||||
NSEvent *e;
|
NSEvent *e;
|
||||||
NSEventModifierFlags m;
|
NSEventModifierFlags m;
|
||||||
uint c, k;
|
uint c, k;
|
||||||
|
|
@ -955,8 +903,7 @@ rpc_setmouse(Client *c, Point p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper for managing input rect approximately
|
// Helper for managing input rect approximately
|
||||||
- (void)resetLastInputRect
|
- (void)resetLastInputRect {
|
||||||
{
|
|
||||||
LOG(@"resetLastInputRect");
|
LOG(@"resetLastInputRect");
|
||||||
_lastInputRect.origin.x = 0.0;
|
_lastInputRect.origin.x = 0.0;
|
||||||
_lastInputRect.origin.y = 0.0;
|
_lastInputRect.origin.y = 0.0;
|
||||||
|
|
@ -964,8 +911,7 @@ rpc_setmouse(Client *c, Point p)
|
||||||
_lastInputRect.size.height = 0.0;
|
_lastInputRect.size.height = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)enlargeLastInputRect:(NSRect)r
|
- (void)enlargeLastInputRect:(NSRect)r {
|
||||||
{
|
|
||||||
r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
|
r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
|
||||||
_lastInputRect = NSUnionRect(_lastInputRect, r);
|
_lastInputRect = NSUnionRect(_lastInputRect, r);
|
||||||
LOG(@"update last input rect (%g, %g, %g, %g)",
|
LOG(@"update last input rect (%g, %g, %g, %g)",
|
||||||
|
|
@ -973,8 +919,7 @@ rpc_setmouse(Client *c, Point p)
|
||||||
_lastInputRect.size.width, _lastInputRect.size.height);
|
_lastInputRect.size.width, _lastInputRect.size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)clearInput
|
- (void)clearInput {
|
||||||
{
|
|
||||||
if(_tmpText.length){
|
if(_tmpText.length){
|
||||||
uint i;
|
uint i;
|
||||||
int l;
|
int l;
|
||||||
|
|
@ -1079,48 +1024,42 @@ keycvt(uint code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// rpc_getsnarf reads the current pasteboard as a plain text string.
|
||||||
|
// Called from an RPC thread with no client lock held.
|
||||||
char*
|
char*
|
||||||
rpc_getsnarf(void)
|
rpc_getsnarf(void)
|
||||||
{
|
{
|
||||||
NSPasteboard *pb;
|
char __block *ret;
|
||||||
NSString *s;
|
|
||||||
|
|
||||||
@autoreleasepool{
|
|
||||||
pb = [NSPasteboard generalPasteboard];
|
|
||||||
|
|
||||||
qlock(&snarfl);
|
|
||||||
s = [pb stringForType:NSPasteboardTypeString];
|
|
||||||
qunlock(&snarfl);
|
|
||||||
|
|
||||||
|
ret = nil;
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^(void) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSPasteboard *pb = [NSPasteboard generalPasteboard];
|
||||||
|
NSString *s = [pb stringForType:NSPasteboardTypeString];
|
||||||
if(s)
|
if(s)
|
||||||
return strdup((char *)[s UTF8String]);
|
ret = strdup((char*)[s UTF8String]);
|
||||||
else
|
|
||||||
return nil;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// rpc_putsnarf writes the given text to the pasteboard.
|
||||||
|
// Called from an RPC thread with no client lock held.
|
||||||
void
|
void
|
||||||
rpc_putsnarf(char *s)
|
rpc_putsnarf(char *s)
|
||||||
{
|
{
|
||||||
NSArray *t;
|
if(s == nil || strlen(s) >= SnarfSize)
|
||||||
NSPasteboard *pb;
|
|
||||||
NSString *str;
|
|
||||||
|
|
||||||
if(strlen(s) >= SnarfSize)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
dispatch_sync(dispatch_get_main_queue(), ^(void) {
|
||||||
@autoreleasepool{
|
@autoreleasepool{
|
||||||
t = [NSArray arrayWithObject:NSPasteboardTypeString];
|
NSArray *t = [NSArray arrayWithObject:NSPasteboardTypeString];
|
||||||
pb = [NSPasteboard generalPasteboard];
|
NSPasteboard *pb = [NSPasteboard generalPasteboard];
|
||||||
str = [[NSString alloc] initWithUTF8String:s];
|
NSString *str = [[NSString alloc] initWithUTF8String:s];
|
||||||
|
|
||||||
qlock(&snarfl);
|
|
||||||
[pb declareTypes:t owner:nil];
|
[pb declareTypes:t owner:nil];
|
||||||
[pb setString:str forType:NSPasteboardTypeString];
|
[pb setString:str forType:NSPasteboardTypeString];
|
||||||
qunlock(&snarfl);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,72 @@ static void runmsg(Client*, Wsysmsg*);
|
||||||
static void replymsg(Client*, Wsysmsg*);
|
static void replymsg(Client*, Wsysmsg*);
|
||||||
static void matchkbd(Client*);
|
static void matchkbd(Client*);
|
||||||
static void matchmouse(Client*);
|
static void matchmouse(Client*);
|
||||||
|
static void serve(void*);
|
||||||
|
static Client *client0;
|
||||||
|
|
||||||
int trace = 0;
|
int trace = 0;
|
||||||
|
|
||||||
void
|
static void
|
||||||
servep9p(Client *c)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
fprint(2, "usage: devdraw (don't run directly)\n");
|
||||||
|
threadexitsall("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Move the protocol off stdin/stdout so that
|
||||||
|
* any inadvertent prints don't screw things up.
|
||||||
|
*/
|
||||||
|
dup(0,3);
|
||||||
|
dup(1,4);
|
||||||
|
close(0);
|
||||||
|
close(1);
|
||||||
|
open("/dev/null", OREAD);
|
||||||
|
open("/dev/null", OWRITE);
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'D': /* for good ps -a listings */
|
||||||
|
break;
|
||||||
|
case 'f': /* fall through for backward compatibility */
|
||||||
|
case 'g':
|
||||||
|
case 'b':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
fmtinstall('W', drawfcallfmt);
|
||||||
|
|
||||||
|
client0 = mallocz(sizeof(Client), 1);
|
||||||
|
if(client0 == nil){
|
||||||
|
fprint(2, "initdraw: allocating client0: out of memory");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
client0->displaydpi = 100;
|
||||||
|
client0->rfd = 3;
|
||||||
|
client0->wfd = 4;
|
||||||
|
|
||||||
|
gfx_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gfx_started(void)
|
||||||
|
{
|
||||||
|
proccreate(serve, client0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
serve(void *v)
|
||||||
|
{
|
||||||
|
Client *c;
|
||||||
uchar buf[4], *mbuf;
|
uchar buf[4], *mbuf;
|
||||||
int nmbuf, n, nn;
|
int nmbuf, n, nn;
|
||||||
Wsysmsg m;
|
Wsysmsg m;
|
||||||
|
|
||||||
fmtinstall('W', drawfcallfmt);
|
c = v;
|
||||||
|
|
||||||
mbuf = nil;
|
mbuf = nil;
|
||||||
nmbuf = 0;
|
nmbuf = 0;
|
||||||
while((n = read(c->rfd, buf, 4)) == 4){
|
while((n = read(c->rfd, buf, 4)) == 4){
|
||||||
|
|
@ -52,6 +106,9 @@ servep9p(Client *c)
|
||||||
if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
|
if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
|
||||||
runmsg(c, &m);
|
runmsg(c, &m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc_shutdown();
|
||||||
|
threadexitsall(nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -79,13 +136,13 @@ runmsg(Client *c, Wsysmsg *m)
|
||||||
switch(m->type){
|
switch(m->type){
|
||||||
case Tinit:
|
case Tinit:
|
||||||
memimageinit();
|
memimageinit();
|
||||||
i = rpc_attachscreen(c, m->label, m->winsize);
|
i = rpc_attach(c, m->label, m->winsize);
|
||||||
_initdisplaymemimage(c, i);
|
draw_initdisplaymemimage(c, i);
|
||||||
replymsg(c, m);
|
replymsg(c, m);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Trdmouse:
|
case Trdmouse:
|
||||||
qlock(&c->inputlk);
|
qlock(&c->eventlk);
|
||||||
c->mousetags.t[c->mousetags.wi++] = m->tag;
|
c->mousetags.t[c->mousetags.wi++] = m->tag;
|
||||||
if(c->mousetags.wi == nelem(c->mousetags.t))
|
if(c->mousetags.wi == nelem(c->mousetags.t))
|
||||||
c->mousetags.wi = 0;
|
c->mousetags.wi = 0;
|
||||||
|
|
@ -93,11 +150,11 @@ runmsg(Client *c, Wsysmsg *m)
|
||||||
sysfatal("too many queued mouse reads");
|
sysfatal("too many queued mouse reads");
|
||||||
c->mouse.stall = 0;
|
c->mouse.stall = 0;
|
||||||
matchmouse(c);
|
matchmouse(c);
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Trdkbd:
|
case Trdkbd:
|
||||||
qlock(&c->inputlk);
|
qlock(&c->eventlk);
|
||||||
c->kbdtags.t[c->kbdtags.wi++] = m->tag;
|
c->kbdtags.t[c->kbdtags.wi++] = m->tag;
|
||||||
if(c->kbdtags.wi == nelem(c->kbdtags.t))
|
if(c->kbdtags.wi == nelem(c->kbdtags.t))
|
||||||
c->kbdtags.wi = 0;
|
c->kbdtags.wi = 0;
|
||||||
|
|
@ -105,7 +162,7 @@ runmsg(Client *c, Wsysmsg *m)
|
||||||
sysfatal("too many queued keyboard reads");
|
sysfatal("too many queued keyboard reads");
|
||||||
c->kbd.stall = 0;
|
c->kbd.stall = 0;
|
||||||
matchkbd(c);
|
matchkbd(c);
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Tmoveto:
|
case Tmoveto:
|
||||||
|
|
@ -148,16 +205,15 @@ runmsg(Client *c, Wsysmsg *m)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Twrsnarf:
|
case Twrsnarf:
|
||||||
putsnarf(m->snarf);
|
rpc_putsnarf(m->snarf);
|
||||||
replymsg(c, m);
|
replymsg(c, m);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Trddraw:
|
case Trddraw:
|
||||||
qlock(&c->inputlk);
|
|
||||||
n = m->count;
|
n = m->count;
|
||||||
if(n > sizeof buf)
|
if(n > sizeof buf)
|
||||||
n = sizeof buf;
|
n = sizeof buf;
|
||||||
n = _drawmsgread(c, buf, n);
|
n = draw_dataread(c, buf, n);
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
replyerror(c, m);
|
replyerror(c, m);
|
||||||
else{
|
else{
|
||||||
|
|
@ -165,16 +221,13 @@ runmsg(Client *c, Wsysmsg *m)
|
||||||
m->data = buf;
|
m->data = buf;
|
||||||
replymsg(c, m);
|
replymsg(c, m);
|
||||||
}
|
}
|
||||||
qunlock(&c->inputlk);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Twrdraw:
|
case Twrdraw:
|
||||||
qlock(&c->inputlk);
|
if(draw_datawrite(c, m->data, m->count) < 0)
|
||||||
if(_drawmsgwrite(c, m->data, m->count) < 0)
|
|
||||||
replyerror(c, m);
|
replyerror(c, m);
|
||||||
else
|
else
|
||||||
replymsg(c, m);
|
replymsg(c, m);
|
||||||
qunlock(&c->inputlk);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Ttop:
|
case Ttop:
|
||||||
|
|
@ -192,13 +245,10 @@ runmsg(Client *c, Wsysmsg *m)
|
||||||
/*
|
/*
|
||||||
* Reply to m.
|
* Reply to m.
|
||||||
*/
|
*/
|
||||||
QLock replylock;
|
|
||||||
static void
|
static void
|
||||||
replymsg(Client *c, Wsysmsg *m)
|
replymsg(Client *c, Wsysmsg *m)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
static uchar *mbuf;
|
|
||||||
static int nmbuf;
|
|
||||||
|
|
||||||
/* T -> R msg */
|
/* T -> R msg */
|
||||||
if(m->type%2 == 0)
|
if(m->type%2 == 0)
|
||||||
|
|
@ -208,18 +258,18 @@ replymsg(Client *c, Wsysmsg *m)
|
||||||
/* copy to output buffer */
|
/* copy to output buffer */
|
||||||
n = sizeW2M(m);
|
n = sizeW2M(m);
|
||||||
|
|
||||||
qlock(&replylock);
|
qlock(&c->wfdlk);
|
||||||
if(n > nmbuf){
|
if(n > c->nmbuf){
|
||||||
free(mbuf);
|
free(c->mbuf);
|
||||||
mbuf = malloc(n);
|
c->mbuf = malloc(n);
|
||||||
if(mbuf == nil)
|
if(c->mbuf == nil)
|
||||||
sysfatal("out of memory");
|
sysfatal("out of memory");
|
||||||
nmbuf = n;
|
c->nmbuf = n;
|
||||||
}
|
}
|
||||||
convW2M(m, mbuf, n);
|
convW2M(m, c->mbuf, n);
|
||||||
if(write(c->wfd, mbuf, n) != n)
|
if(write(c->wfd, c->mbuf, n) != n)
|
||||||
sysfatal("write: %r");
|
sysfatal("write: %r");
|
||||||
qunlock(&replylock);
|
qunlock(&c->wfdlk);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -245,13 +295,13 @@ matchkbd(Client *c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchmouse matches queued mouse reads with queued mouse events.
|
// matchmouse matches queued mouse reads with queued mouse events.
|
||||||
// It must be called with c->inputlk held.
|
// It must be called with c->eventlk held.
|
||||||
static void
|
static void
|
||||||
matchmouse(Client *c)
|
matchmouse(Client *c)
|
||||||
{
|
{
|
||||||
Wsysmsg m;
|
Wsysmsg m;
|
||||||
|
|
||||||
if(canqlock(&c->inputlk)) {
|
if(canqlock(&c->eventlk)) {
|
||||||
fprint(2, "misuse of matchmouse\n");
|
fprint(2, "misuse of matchmouse\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
@ -280,7 +330,7 @@ gfx_mousetrack(Client *c, int x, int y, int b, uint ms)
|
||||||
{
|
{
|
||||||
Mouse *m;
|
Mouse *m;
|
||||||
|
|
||||||
qlock(&c->inputlk);
|
qlock(&c->eventlk);
|
||||||
if(x < c->mouserect.min.x)
|
if(x < c->mouserect.min.x)
|
||||||
x = c->mouserect.min.x;
|
x = c->mouserect.min.x;
|
||||||
if(x > c->mouserect.max.x)
|
if(x > c->mouserect.max.x)
|
||||||
|
|
@ -312,15 +362,15 @@ gfx_mousetrack(Client *c, int x, int y, int b, uint ms)
|
||||||
}
|
}
|
||||||
matchmouse(c);
|
matchmouse(c);
|
||||||
}
|
}
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// kputc adds ch to the keyboard buffer.
|
// kputc adds ch to the keyboard buffer.
|
||||||
// It must be called with c->inputlk held.
|
// It must be called with c->eventlk held.
|
||||||
static void
|
static void
|
||||||
kputc(Client *c, int ch)
|
kputc(Client *c, int ch)
|
||||||
{
|
{
|
||||||
if(canqlock(&c->inputlk)) {
|
if(canqlock(&c->eventlk)) {
|
||||||
fprint(2, "misuse of kputc\n");
|
fprint(2, "misuse of kputc\n");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
@ -339,12 +389,12 @@ kputc(Client *c, int ch)
|
||||||
void
|
void
|
||||||
gfx_abortcompose(Client *c)
|
gfx_abortcompose(Client *c)
|
||||||
{
|
{
|
||||||
qlock(&c->inputlk);
|
qlock(&c->eventlk);
|
||||||
if(c->kbd.alting) {
|
if(c->kbd.alting) {
|
||||||
c->kbd.alting = 0;
|
c->kbd.alting = 0;
|
||||||
c->kbd.nk = 0;
|
c->kbd.nk = 0;
|
||||||
}
|
}
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
}
|
}
|
||||||
|
|
||||||
// gfx_keystroke records a single-rune keystroke.
|
// gfx_keystroke records a single-rune keystroke.
|
||||||
|
|
@ -354,11 +404,11 @@ gfx_keystroke(Client *c, int ch)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
qlock(&c->inputlk);
|
qlock(&c->eventlk);
|
||||||
if(ch == Kalt){
|
if(ch == Kalt){
|
||||||
c->kbd.alting = !c->kbd.alting;
|
c->kbd.alting = !c->kbd.alting;
|
||||||
c->kbd.nk = 0;
|
c->kbd.nk = 0;
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(ch == Kcmd+'r') {
|
if(ch == Kcmd+'r') {
|
||||||
|
|
@ -368,24 +418,24 @@ gfx_keystroke(Client *c, int ch)
|
||||||
c->forcedpi = 100;
|
c->forcedpi = 100;
|
||||||
else
|
else
|
||||||
c->forcedpi = 225;
|
c->forcedpi = 225;
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
rpc_resizeimg(c);
|
rpc_resizeimg(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!c->kbd.alting){
|
if(!c->kbd.alting){
|
||||||
kputc(c, ch);
|
kputc(c, ch);
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen
|
if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen
|
||||||
c->kbd.nk = 0;
|
c->kbd.nk = 0;
|
||||||
c->kbd.k[c->kbd.nk++] = ch;
|
c->kbd.k[c->kbd.nk++] = ch;
|
||||||
ch = _latin1(c->kbd.k, c->kbd.nk);
|
ch = latin1(c->kbd.k, c->kbd.nk);
|
||||||
if(ch > 0){
|
if(ch > 0){
|
||||||
c->kbd.alting = 0;
|
c->kbd.alting = 0;
|
||||||
kputc(c, ch);
|
kputc(c, ch);
|
||||||
c->kbd.nk = 0;
|
c->kbd.nk = 0;
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(ch == -1){
|
if(ch == -1){
|
||||||
|
|
@ -393,10 +443,10 @@ gfx_keystroke(Client *c, int ch)
|
||||||
for(i=0; i<c->kbd.nk; i++)
|
for(i=0; i<c->kbd.nk; i++)
|
||||||
kputc(c, c->kbd.k[i]);
|
kputc(c, c->kbd.k[i]);
|
||||||
c->kbd.nk = 0;
|
c->kbd.nk = 0;
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// need more input
|
// need more input
|
||||||
qunlock(&c->inputlk);
|
qunlock(&c->eventlk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -733,6 +733,6 @@ _xreplacescreenimage(void)
|
||||||
XFreePixmap(_x.display, _x.nextscreenpm);
|
XFreePixmap(_x.display, _x.nextscreenpm);
|
||||||
_x.nextscreenpm = pixmap;
|
_x.nextscreenpm = pixmap;
|
||||||
_x.screenr = r;
|
_x.screenr = r;
|
||||||
_drawreplacescreenimage(m);
|
gfx_replacescreenimage(m);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ abortcompose(void)
|
||||||
|
|
||||||
static Rune* sendrune(Rune);
|
static Rune* sendrune(Rune);
|
||||||
|
|
||||||
extern int _latin1(Rune*, int);
|
extern int latin1(Rune*, int);
|
||||||
static Rune*
|
static Rune*
|
||||||
xtoplan9latin1(XEvent *e)
|
xtoplan9latin1(XEvent *e)
|
||||||
{
|
{
|
||||||
|
|
@ -182,7 +182,7 @@ sendrune(Rune r)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
k[nk++] = r;
|
k[nk++] = r;
|
||||||
n = _latin1(k, nk);
|
n = latin1(k, nk);
|
||||||
if(n > 0){
|
if(n > 0){
|
||||||
alting = 0;
|
alting = 0;
|
||||||
k[0] = n;
|
k[0] = n;
|
||||||
|
|
|
||||||
|
|
@ -365,7 +365,7 @@ runmsg(Wsysmsg *m)
|
||||||
n = m->count;
|
n = m->count;
|
||||||
if(n > sizeof buf)
|
if(n > sizeof buf)
|
||||||
n = sizeof buf;
|
n = sizeof buf;
|
||||||
n = _drawmsgread(buf, n);
|
n = draw_dataread(buf, n);
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
replyerror(m);
|
replyerror(m);
|
||||||
else{
|
else{
|
||||||
|
|
@ -376,7 +376,7 @@ runmsg(Wsysmsg *m)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Twrdraw:
|
case Twrdraw:
|
||||||
if(_drawmsgwrite(m->data, m->count) < 0)
|
if(draw_datawrite(m->data, m->count) < 0)
|
||||||
replyerror(m);
|
replyerror(m);
|
||||||
else
|
else
|
||||||
replymsg(m);
|
replymsg(m);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue