aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/devdraw/devdraw.c130
-rw-r--r--src/cmd/devdraw/devdraw.h91
-rw-r--r--src/cmd/devdraw/latin1.c2
-rw-r--r--src/cmd/devdraw/mac-screen.m271
-rw-r--r--src/cmd/devdraw/srv.c138
-rw-r--r--src/cmd/devdraw/x11-init.c2
-rw-r--r--src/cmd/devdraw/x11-itrans.c4
-rw-r--r--src/cmd/devdraw/x11-srv.c4
8 files changed, 329 insertions, 313 deletions
diff --git a/src/cmd/devdraw/devdraw.c b/src/cmd/devdraw/devdraw.c
index 77a3f44a..e3040779 100644
--- a/src/cmd/devdraw/devdraw.c
+++ b/src/cmd/devdraw/devdraw.c
@@ -14,14 +14,12 @@
#include <drawfcall.h>
#include "devdraw.h"
-static Draw sdraw;
-Client *client0;
static int drawuninstall(Client*, int);
static Memimage* drawinstall(Client*, int, Memimage*, DScreen*);
static void drawfreedimage(Client*, DImage*);
void
-_initdisplaymemimage(Client *c, Memimage *m)
+draw_initdisplaymemimage(Client *c, Memimage *m)
{
c->screenimage = m;
m->screenref = 1;
@@ -30,10 +28,10 @@ _initdisplaymemimage(Client *c, Memimage *m)
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.
void
-_drawreplacescreenimage(Client *c, Memimage *m)
+gfx_replacescreenimage(Client *c, Memimage *m)
{
/*
* Replace the screen image because the screen
@@ -49,21 +47,21 @@ _drawreplacescreenimage(Client *c, Memimage *m)
*/
Memimage *om;
- qlock(&c->inputlk);
- qlock(&sdraw.lk);
+ qlock(&c->drawlk);
om = c->screenimage;
c->screenimage = m;
m->screenref = 1;
- c->mouse.resized = 1;
if(om && --om->screenref == 0){
_freememimage(om);
}
- qunlock(&sdraw.lk);
- qunlock(&c->inputlk);
+ qunlock(&c->drawlk);
+
+ qlock(&c->eventlk);
+ c->mouse.resized = 1;
+ qunlock(&c->eventlk);
}
-static
-void
+static void
drawrefreshscreen(DImage *l, Client *client)
{
while(l != nil && l->dscreen == nil)
@@ -72,8 +70,7 @@ drawrefreshscreen(DImage *l, Client *client)
l->dscreen->owner->refreshme = 1;
}
-static
-void
+static void
drawrefresh(Memimage *m, Rectangle r, void *v)
{
Refx *x;
@@ -106,7 +103,7 @@ static void
addflush(Client *c, Rectangle r)
{
int abb, ar, anbb;
- Rectangle nbb;
+ Rectangle nbb, fr;
if(/*sdraw.softscreen==0 ||*/ !rectclip(&r, c->screenimage->r))
return;
@@ -140,14 +137,20 @@ addflush(Client *c, Rectangle r)
return;
}
/* emit current state */
- if(c->flushrect.min.x < c->flushrect.max.x)
- rpc_flushmemscreen(c, c->flushrect);
+ fr = c->flushrect;
c->flushrect = r;
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
-void
+static void
dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
{
Memlayer *l;
@@ -173,17 +176,24 @@ dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
addflush(c, r);
}
-static
-void
+static void
drawflush(Client *c)
{
- if(c->flushrect.min.x < c->flushrect.max.x)
- rpc_flushmemscreen(c, c->flushrect);
+ Rectangle r;
+
+ r = c->flushrect;
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
-int
+static int
drawcmp(char *a, char *b, int n)
{
if(strlen(a) != n)
@@ -191,8 +201,7 @@ drawcmp(char *a, char *b, int n)
return memcmp(a, b, n);
}
-static
-DName*
+static DName*
drawlookupname(Client *client, int n, char *str)
{
DName *name, *ename;
@@ -205,8 +214,7 @@ drawlookupname(Client *client, int n, char *str)
return 0;
}
-static
-int
+static int
drawgoodname(Client *client, DImage *d)
{
DName *n;
@@ -224,8 +232,7 @@ drawgoodname(Client *client, DImage *d)
return 1;
}
-static
-DImage*
+static DImage*
drawlookup(Client *client, int id, int checkname)
{
DImage *d;
@@ -246,8 +253,7 @@ drawlookup(Client *client, int id, int checkname)
return 0;
}
-static
-DScreen*
+static DScreen*
drawlookupdscreen(Client *c, int id)
{
DScreen *s;
@@ -261,8 +267,7 @@ drawlookupdscreen(Client *c, int id)
return 0;
}
-static
-DScreen*
+static DScreen*
drawlookupscreen(Client *client, int id, CScreen **cs)
{
CScreen *s;
@@ -279,8 +284,7 @@ drawlookupscreen(Client *client, int id, CScreen **cs)
return 0;
}
-static
-Memimage*
+static Memimage*
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
{
DImage *d;
@@ -304,8 +308,7 @@ drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
return i;
}
-static
-Memscreen*
+static Memscreen*
drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
{
Memscreen *s;
@@ -358,8 +361,7 @@ drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *df
return d->screen;
}
-static
-void
+static void
drawdelname(Client *client, DName *name)
{
int i;
@@ -369,8 +371,7 @@ drawdelname(Client *client, DName *name)
client->nname--;
}
-static
-void
+static void
drawfreedscreen(Client *client, DScreen *this)
{
DScreen *ds, *next;
@@ -406,8 +407,7 @@ drawfreedscreen(Client *client, DScreen *this)
free(this);
}
-static
-void
+static void
drawfreedimage(Client *client, DImage *dimage)
{
int i;
@@ -456,8 +456,7 @@ drawfreedimage(Client *client, DImage *dimage)
free(dimage);
}
-static
-void
+static void
drawuninstallscreen(Client *client, CScreen *this)
{
CScreen *cs, *next;
@@ -480,8 +479,7 @@ drawuninstallscreen(Client *client, CScreen *this)
}
}
-static
-int
+static int
drawuninstall(Client *client, int id)
{
DImage *d, **l;
@@ -496,8 +494,7 @@ drawuninstall(Client *client, int id)
return -1;
}
-static
-int
+static int
drawaddname(Client *client, DImage *di, int n, char *str, char **err)
{
DName *name, *ename, *new, *t;
@@ -541,8 +538,7 @@ drawclientop(Client *cl)
return op;
}
-static
-Memimage*
+static Memimage*
drawimage(Client *client, uchar *a)
{
DImage *d;
@@ -553,8 +549,7 @@ drawimage(Client *client, uchar *a)
return d->image;
}
-static
-void
+static void
drawrectangle(Rectangle *r, uchar *a)
{
r->min.x = BGLONG(a+0*4);
@@ -563,16 +558,14 @@ drawrectangle(Rectangle *r, uchar *a)
r->max.y = BGLONG(a+3*4);
}
-static
-void
+static void
drawpoint(Point *p, uchar *a)
{
p->x = BGLONG(a+0*4);
p->y = BGLONG(a+1*4);
}
-static
-Point
+static Point
drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
{
FChar *fc;
@@ -592,8 +585,7 @@ drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int ind
return p;
}
-static
-uchar*
+static uchar*
drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
{
int b, x;
@@ -619,9 +611,9 @@ drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
}
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){
werrstr("no draw data");
goto err;
@@ -634,16 +626,16 @@ _drawmsgread(Client *cl, void *a, int n)
memmove(a, cl->readdata, cl->nreaddata);
free(cl->readdata);
cl->readdata = nil;
- qunlock(&sdraw.lk);
+ qunlock(&cl->drawlk);
return n;
err:
- qunlock(&sdraw.lk);
+ qunlock(&cl->drawlk);
return -1;
}
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;
int c, ci, doflush, dstid, e0, e1, esize, j, m;
@@ -663,7 +655,7 @@ _drawmsgwrite(Client *client, void *v, int n)
Refreshfn reffn;
Refx *refx;
- qlock(&sdraw.lk);
+ qlock(&client->drawlk);
a = v;
m = 0;
oldn = n;
@@ -1436,7 +1428,7 @@ _drawmsgwrite(Client *client, void *v, int n)
continue;
}
}
- qunlock(&sdraw.lk);
+ qunlock(&client->drawlk);
return oldn - n;
Enodrawimage:
@@ -1506,6 +1498,6 @@ Ebadarg:
error:
werrstr("%s", err);
- qunlock(&sdraw.lk);
+ qunlock(&client->drawlk);
return -1;
}
diff --git a/src/cmd/devdraw/devdraw.h b/src/cmd/devdraw/devdraw.h
index 30586228..dd7fc8ba 100644
--- a/src/cmd/devdraw/devdraw.h
+++ b/src/cmd/devdraw/devdraw.h
@@ -7,7 +7,6 @@ typedef struct Mousebuf Mousebuf;
typedef struct Tagbuf Tagbuf;
typedef struct Client Client;
-typedef struct Draw Draw;
typedef struct DImage DImage;
typedef struct DScreen DScreen;
typedef struct CScreen CScreen;
@@ -16,11 +15,6 @@ typedef struct Refresh Refresh;
typedef struct Refx Refx;
typedef struct DName DName;
-struct Draw
-{
- QLock lk;
-};
-
struct Kbdbuf
{
Rune r[256];
@@ -51,6 +45,19 @@ struct Tagbuf
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;*/
DImage* dimage[NHASH];
CScreen* cscreen;
@@ -64,7 +71,6 @@ struct Client
int refreshme;
int infoid;
int op;
-
int displaydpi;
int forcedpi;
int waste;
@@ -75,11 +81,11 @@ struct Client
DName* name;
int namevers;
- int rfd;
- int wfd;
+ // Only accessed/modified by the graphics thread.
const void* view;
- QLock inputlk;
+ // eventlk protects the keyboard and mouse events.
+ QLock eventlk;
Kbdbuf kbd;
Mousebuf mouse;
Tagbuf kbdtags;
@@ -157,30 +163,59 @@ struct DScreen
DScreen* next;
};
-int _drawmsgread(Client*, void*, int);
-int _drawmsgwrite(Client*, void*, int);
-void _initdisplaymemimage(Client*, Memimage*);
-void _drawreplacescreenimage(Client*, Memimage*);
-
-int _latin1(Rune*, int);
-int parsewinsize(char*, Rectangle*, int*);
-int mouseswap(int);
-
+// For the most part, the graphics driver-specific code in files
+// like mac-screen.m runs in the graphics library's main thread,
+// while the RPC service code in srv.c runs on the RPC service thread.
+// The exceptions in each file, which are called by the other,
+// are marked with special prefixes: gfx_* indicates code that
+// is in srv.c but nonetheless runs on the main graphics thread,
+// while rpc_* indicates code that is in, say, mac-screen.m but
+// 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_keystroke(Client*, int);
+void gfx_main(void);
void gfx_mousetrack(Client*, int, int, int, uint);
+void gfx_replacescreenimage(Client*, Memimage*);
+void gfx_started(void);
-void rpc_setmouse(Client*, Point);
-void rpc_setcursor(Client*, Cursor*, Cursor2*);
-void rpc_setlabel(Client*, char*);
+// rpc_* routines are called on the RPC thread,
+// invoked by the RPC server code to do graphics work.
+// No locks are held on entry.
+Memimage *rpc_attach(Client*, char*, char*);
+char* rpc_getsnarf(void);
+void rpc_putsnarf(char*);
void rpc_resizeimg(Client*);
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*);
-char* rpc_getsnarf(void);
-void rpc_putsnarf(char*);
-Memimage *rpc_attachscreen(Client*, char*, char*);
-void rpc_flushmemscreen(Client*, Rectangle);
+void rpc_main(void);
+
+// TODO: rpc_flush is called from draw_datawrite,
+// which holds c->drawlk. Is this OK?
+void rpc_flush(Client*, Rectangle);
-extern Client *client0;
+// 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*);
diff --git a/src/cmd/devdraw/latin1.c b/src/cmd/devdraw/latin1.c
index 2fa9e29d..a3d13a08 100644
--- a/src/cmd/devdraw/latin1.c
+++ b/src/cmd/devdraw/latin1.c
@@ -46,7 +46,7 @@ unicode(Rune *k)
* is minus the required n.
*/
int
-_latin1(Rune *k, int n)
+latin1(Rune *k, int n)
{
struct cvlist *l;
int c;
diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m
index d756d3d7..2ce6bb34 100644
--- a/src/cmd/devdraw/mac-screen.m
+++ b/src/cmd/devdraw/mac-screen.m
@@ -34,13 +34,6 @@ static void setprocname(const char*);
static uint keycvt(uint);
static uint msec(void);
-void
-usage(void)
-{
- fprint(2, "usage: devdraw (don't run directly)\n");
- threadexitsall("usage");
-}
-
@class DrawView;
@class DrawLayer;
@@ -49,43 +42,9 @@ usage(void)
static AppDelegate *myApp = NULL;
-
-static QLock snarfl;
-
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);
@autoreleasepool{
@@ -97,12 +56,10 @@ threadmain(int argc, char **argv)
}
}
+
void
-callservep9p(void *v)
+rpc_shutdown(void)
{
- USED(v);
-
- servep9p(client0);
[NSApp terminate:myApp];
}
@@ -128,8 +85,8 @@ callservep9p(void *v)
i = [[NSImage alloc] initWithData:d];
[NSApp setApplicationIconImage:i];
[[NSApp dockTile] display];
-
- proccreate(callservep9p, nil, 0);
+
+ gfx_started();
}
- (NSApplicationPresentationOptions)window:(id)arg
@@ -242,10 +199,10 @@ callservep9p(void *v)
- (BOOL)isFlipped { 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).
Memimage*
-rpc_attachscreen(Client *c, char *label, char *winsize)
+rpc_attach(Client *c, char *label, char *winsize)
{
LOG(@"attachscreen(%s, %s)", label, winsize);
@@ -468,71 +425,73 @@ rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
}
- (void)initimg {
-@autoreleasepool{
- CGFloat scale;
- NSSize size;
- MTLTextureDescriptor *textureDesc;
-
- size = [self convertSizeToBacking:[self bounds].size];
- self.client->mouserect = Rect(0, 0, size.width, size.height);
-
- LOG(@"initimg %.0f %.0f", size.width, size.height);
-
- self.img = allocmemimage(self.client->mouserect, XRGB32);
- if(self.img == nil)
- panic("allocmemimage: %r");
- if(self.img->data == nil)
- panic("img->data == nil");
-
- textureDesc = [MTLTextureDescriptor
- texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
- width:size.width
- height:size.height
- mipmapped:NO];
- textureDesc.allowGPUOptimizedContents = YES;
- textureDesc.usage = MTLTextureUsageShaderRead;
- textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
- self.dlayer.texture = [self.dlayer.device newTextureWithDescriptor:textureDesc];
-
- scale = [self.win backingScaleFactor];
- [self.dlayer setDrawableSize:size];
- [self.dlayer setContentsScale:scale];
-
- // NOTE: This is not really the display DPI.
- // On retina, scale is 2; otherwise it is 1.
- // This formula gives us 220 for retina, 110 otherwise.
- // That's not quite right but it's close to correct.
- // https://en.wikipedia.org/wiki/Retina_display#Models
- self.client->displaydpi = scale * 110;
-}
- LOG(@"initimg return");
+ @autoreleasepool {
+ CGFloat scale;
+ NSSize size;
+ MTLTextureDescriptor *textureDesc;
+
+ size = [self convertSizeToBacking:[self bounds].size];
+ self.client->mouserect = Rect(0, 0, size.width, size.height);
+
+ LOG(@"initimg %.0f %.0f", size.width, size.height);
+
+ self.img = allocmemimage(self.client->mouserect, XRGB32);
+ if(self.img == nil)
+ panic("allocmemimage: %r");
+ if(self.img->data == nil)
+ panic("img->data == nil");
+
+ textureDesc = [MTLTextureDescriptor
+ texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+ width:size.width
+ height:size.height
+ mipmapped:NO];
+ textureDesc.allowGPUOptimizedContents = YES;
+ textureDesc.usage = MTLTextureUsageShaderRead;
+ textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
+ self.dlayer.texture = [self.dlayer.device newTextureWithDescriptor:textureDesc];
+
+ scale = [self.win backingScaleFactor];
+ [self.dlayer setDrawableSize:size];
+ [self.dlayer setContentsScale:scale];
+
+ // NOTE: This is not really the display DPI.
+ // On retina, scale is 2; otherwise it is 1.
+ // This formula gives us 220 for retina, 110 otherwise.
+ // That's not quite right but it's close to correct.
+ // https://en.wikipedia.org/wiki/Retina_display#Models
+ self.client->displaydpi = scale * 110;
+ }
}
-// 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.
// Called from an RPC thread with no client lock held.
void
-rpc_flushmemscreen(Client *client, Rectangle r)
+rpc_flush(Client *client, Rectangle r)
{
DrawView *view = (__bridge DrawView*)client->view;
dispatch_async(dispatch_get_main_queue(), ^(void){
- [view flushmemscreen:r];
+ [view flush:r];
});
}
-- (void)flushmemscreen:(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;
- }
-
+- (void)flush:(Rectangle)r {
@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
replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
mipmapLevel:0
withBytes:byteaddr(self.img, Pt(r.min.x, r.min.y))
bytesPerRow:self.img->width*sizeof(u32int)];
+ qunlock(&self.client->drawlk);
NSRect nr = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
dispatch_time_t time;
@@ -565,7 +524,7 @@ rpc_resizeimg(Client *c)
- (void)resizeimg {
[self initimg];
- _drawreplacescreenimage(self.client, self.img);
+ gfx_replacescreenimage(self.client, self.img);
[self sendmouse:0];
}
@@ -750,7 +709,7 @@ rpc_setmouse(Client *c, Point p)
});
}
--(void)setmouse:(Point)p {
+- (void)setmouse:(Point)p {
@autoreleasepool{
NSPoint q;
@@ -782,21 +741,10 @@ rpc_setmouse(Client *c, Point p)
}
// conforms to protocol NSTextInputClient
-- (BOOL)hasMarkedText
-{
- LOG(@"hasMarkedText");
- return _markedRange.location != NSNotFound;
-}
-- (NSRange)markedRange
-{
- LOG(@"markedRange");
- return _markedRange;
-}
-- (NSRange)selectedRange
-{
- LOG(@"selectedRange");
- return _selectedRange;
-}
+- (BOOL)hasMarkedText { return _markedRange.location != NSNotFound; }
+- (NSRange)markedRange { return _markedRange; }
+- (NSRange)selectedRange { return _selectedRange; }
+
- (void)setMarkedText:(id)string
selectedRange:(NSRange)sRange
replacementRange:(NSRange)rRange
@@ -861,8 +809,8 @@ rpc_setmouse(Client *c, Point p)
_markedRange.location, _markedRange.length,
_selectedRange.location, _selectedRange.length);
}
-- (void)unmarkText
-{
+
+- (void)unmarkText {
//NSUInteger i;
NSUInteger len;
@@ -874,12 +822,13 @@ rpc_setmouse(Client *c, Point p)
_markedRange = NSMakeRange(NSNotFound, 0);
_selectedRange = NSMakeRange(0, 0);
}
-- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
-{
+
+- (NSArray<NSAttributedStringKey>*)validAttributesForMarkedText {
LOG(@"validAttributesForMarkedText");
return @[];
}
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
+
+- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)r
actualRange:(NSRangePointer)actualRange
{
NSRange sr;
@@ -899,9 +848,8 @@ rpc_setmouse(Client *c, Point p)
LOG(@" return %@", s);
return s;
}
-- (void)insertText:(id)s
- replacementRange:(NSRange)r
-{
+
+- (void)insertText:(id)s replacementRange:(NSRange)r {
NSUInteger i;
NSUInteger len;
@@ -916,22 +864,22 @@ rpc_setmouse(Client *c, Point p)
_markedRange = NSMakeRange(NSNotFound, 0);
_selectedRange = NSMakeRange(0, 0);
}
+
- (NSUInteger)characterIndexForPoint:(NSPoint)point
{
LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
return 0;
}
-- (NSRect)firstRectForCharacterRange:(NSRange)r
- actualRange:(NSRangePointer)actualRange
-{
+
+- (NSRect)firstRectForCharacterRange:(NSRange)r actualRange:(NSRangePointer)actualRange {
LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
r.location, r.length, actualRange->location, actualRange->length);
if(actualRange)
*actualRange = r;
return [[self window] convertRectToScreen:_lastInputRect];
}
-- (void)doCommandBySelector:(SEL)s
-{
+
+- (void)doCommandBySelector:(SEL)s {
NSEvent *e;
NSEventModifierFlags m;
uint c, k;
@@ -955,8 +903,7 @@ rpc_setmouse(Client *c, Point p)
}
// Helper for managing input rect approximately
-- (void)resetLastInputRect
-{
+- (void)resetLastInputRect {
LOG(@"resetLastInputRect");
_lastInputRect.origin.x = 0.0;
_lastInputRect.origin.y = 0.0;
@@ -964,8 +911,7 @@ rpc_setmouse(Client *c, Point p)
_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;
_lastInputRect = NSUnionRect(_lastInputRect, r);
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);
}
-- (void)clearInput
-{
+- (void)clearInput {
if(_tmpText.length){
uint i;
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*
rpc_getsnarf(void)
{
- NSPasteboard *pb;
- NSString *s;
-
- @autoreleasepool{
- pb = [NSPasteboard generalPasteboard];
-
- qlock(&snarfl);
- s = [pb stringForType:NSPasteboardTypeString];
- qunlock(&snarfl);
-
- if(s)
- return strdup((char *)[s UTF8String]);
- else
- return nil;
- }
+ char __block *ret;
+
+ ret = nil;
+ dispatch_sync(dispatch_get_main_queue(), ^(void) {
+ @autoreleasepool {
+ NSPasteboard *pb = [NSPasteboard generalPasteboard];
+ NSString *s = [pb stringForType:NSPasteboardTypeString];
+ if(s)
+ ret = strdup((char*)[s UTF8String]);
+ }
+ });
+ return ret;
}
-// TODO
+// rpc_putsnarf writes the given text to the pasteboard.
+// Called from an RPC thread with no client lock held.
void
rpc_putsnarf(char *s)
{
- NSArray *t;
- NSPasteboard *pb;
- NSString *str;
-
- if(strlen(s) >= SnarfSize)
+ if(s == nil || strlen(s) >= SnarfSize)
return;
- @autoreleasepool{
- t = [NSArray arrayWithObject:NSPasteboardTypeString];
- pb = [NSPasteboard generalPasteboard];
- str = [[NSString alloc] initWithUTF8String:s];
-
- qlock(&snarfl);
- [pb declareTypes:t owner:nil];
- [pb setString:str forType:NSPasteboardTypeString];
- qunlock(&snarfl);
- }
+ dispatch_sync(dispatch_get_main_queue(), ^(void) {
+ @autoreleasepool{
+ NSArray *t = [NSArray arrayWithObject:NSPasteboardTypeString];
+ NSPasteboard *pb = [NSPasteboard generalPasteboard];
+ NSString *str = [[NSString alloc] initWithUTF8String:s];
+ [pb declareTypes:t owner:nil];
+ [pb setString:str forType:NSPasteboardTypeString];
+ }
+ });
}
static void
diff --git a/src/cmd/devdraw/srv.c b/src/cmd/devdraw/srv.c
index 0e7540be..5169c113 100644
--- a/src/cmd/devdraw/srv.c
+++ b/src/cmd/devdraw/srv.c
@@ -18,18 +18,72 @@ static void runmsg(Client*, Wsysmsg*);
static void replymsg(Client*, Wsysmsg*);
static void matchkbd(Client*);
static void matchmouse(Client*);
+static void serve(void*);
+static Client *client0;
int trace = 0;
+static void
+usage(void)
+{
+ fprint(2, "usage: devdraw (don't run directly)\n");
+ threadexitsall("usage");
+}
+
void
-servep9p(Client *c)
+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;
int nmbuf, n, nn;
Wsysmsg m;
- fmtinstall('W', drawfcallfmt);
-
+ c = v;
mbuf = nil;
nmbuf = 0;
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);
runmsg(c, &m);
}
+
+ rpc_shutdown();
+ threadexitsall(nil);
}
static void
@@ -79,13 +136,13 @@ runmsg(Client *c, Wsysmsg *m)
switch(m->type){
case Tinit:
memimageinit();
- i = rpc_attachscreen(c, m->label, m->winsize);
- _initdisplaymemimage(c, i);
+ i = rpc_attach(c, m->label, m->winsize);
+ draw_initdisplaymemimage(c, i);
replymsg(c, m);
break;
case Trdmouse:
- qlock(&c->inputlk);
+ qlock(&c->eventlk);
c->mousetags.t[c->mousetags.wi++] = m->tag;
if(c->mousetags.wi == nelem(c->mousetags.t))
c->mousetags.wi = 0;
@@ -93,11 +150,11 @@ runmsg(Client *c, Wsysmsg *m)
sysfatal("too many queued mouse reads");
c->mouse.stall = 0;
matchmouse(c);
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
break;
case Trdkbd:
- qlock(&c->inputlk);
+ qlock(&c->eventlk);
c->kbdtags.t[c->kbdtags.wi++] = m->tag;
if(c->kbdtags.wi == nelem(c->kbdtags.t))
c->kbdtags.wi = 0;
@@ -105,7 +162,7 @@ runmsg(Client *c, Wsysmsg *m)
sysfatal("too many queued keyboard reads");
c->kbd.stall = 0;
matchkbd(c);
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
break;
case Tmoveto:
@@ -148,16 +205,15 @@ runmsg(Client *c, Wsysmsg *m)
break;
case Twrsnarf:
- putsnarf(m->snarf);
+ rpc_putsnarf(m->snarf);
replymsg(c, m);
break;
case Trddraw:
- qlock(&c->inputlk);
n = m->count;
if(n > sizeof buf)
n = sizeof buf;
- n = _drawmsgread(c, buf, n);
+ n = draw_dataread(c, buf, n);
if(n < 0)
replyerror(c, m);
else{
@@ -165,16 +221,13 @@ runmsg(Client *c, Wsysmsg *m)
m->data = buf;
replymsg(c, m);
}
- qunlock(&c->inputlk);
break;
case Twrdraw:
- qlock(&c->inputlk);
- if(_drawmsgwrite(c, m->data, m->count) < 0)
+ if(draw_datawrite(c, m->data, m->count) < 0)
replyerror(c, m);
else
replymsg(c, m);
- qunlock(&c->inputlk);
break;
case Ttop:
@@ -192,13 +245,10 @@ runmsg(Client *c, Wsysmsg *m)
/*
* Reply to m.
*/
-QLock replylock;
static void
replymsg(Client *c, Wsysmsg *m)
{
int n;
- static uchar *mbuf;
- static int nmbuf;
/* T -> R msg */
if(m->type%2 == 0)
@@ -208,18 +258,18 @@ replymsg(Client *c, Wsysmsg *m)
/* copy to output buffer */
n = sizeW2M(m);
- qlock(&replylock);
- if(n > nmbuf){
- free(mbuf);
- mbuf = malloc(n);
- if(mbuf == nil)
+ qlock(&c->wfdlk);
+ if(n > c->nmbuf){
+ free(c->mbuf);
+ c->mbuf = malloc(n);
+ if(c->mbuf == nil)
sysfatal("out of memory");
- nmbuf = n;
+ c->nmbuf = n;
}
- convW2M(m, mbuf, n);
- if(write(c->wfd, mbuf, n) != n)
+ convW2M(m, c->mbuf, n);
+ if(write(c->wfd, c->mbuf, n) != n)
sysfatal("write: %r");
- qunlock(&replylock);
+ qunlock(&c->wfdlk);
}
/*
@@ -245,13 +295,13 @@ matchkbd(Client *c)
}
// 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
matchmouse(Client *c)
{
Wsysmsg m;
- if(canqlock(&c->inputlk)) {
+ if(canqlock(&c->eventlk)) {
fprint(2, "misuse of matchmouse\n");
abort();
}
@@ -280,7 +330,7 @@ gfx_mousetrack(Client *c, int x, int y, int b, uint ms)
{
Mouse *m;
- qlock(&c->inputlk);
+ qlock(&c->eventlk);
if(x < c->mouserect.min.x)
x = c->mouserect.min.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);
}
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
}
// 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
kputc(Client *c, int ch)
{
- if(canqlock(&c->inputlk)) {
+ if(canqlock(&c->eventlk)) {
fprint(2, "misuse of kputc\n");
abort();
}
@@ -339,12 +389,12 @@ kputc(Client *c, int ch)
void
gfx_abortcompose(Client *c)
{
- qlock(&c->inputlk);
+ qlock(&c->eventlk);
if(c->kbd.alting) {
c->kbd.alting = 0;
c->kbd.nk = 0;
}
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
}
// gfx_keystroke records a single-rune keystroke.
@@ -354,11 +404,11 @@ gfx_keystroke(Client *c, int ch)
{
int i;
- qlock(&c->inputlk);
+ qlock(&c->eventlk);
if(ch == Kalt){
c->kbd.alting = !c->kbd.alting;
c->kbd.nk = 0;
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
return;
}
if(ch == Kcmd+'r') {
@@ -368,24 +418,24 @@ gfx_keystroke(Client *c, int ch)
c->forcedpi = 100;
else
c->forcedpi = 225;
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
rpc_resizeimg(c);
return;
}
if(!c->kbd.alting){
kputc(c, ch);
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
return;
}
if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen
c->kbd.nk = 0;
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){
c->kbd.alting = 0;
kputc(c, ch);
c->kbd.nk = 0;
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
return;
}
if(ch == -1){
@@ -393,10 +443,10 @@ gfx_keystroke(Client *c, int ch)
for(i=0; i<c->kbd.nk; i++)
kputc(c, c->kbd.k[i]);
c->kbd.nk = 0;
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
return;
}
// need more input
- qunlock(&c->inputlk);
+ qunlock(&c->eventlk);
return;
}
diff --git a/src/cmd/devdraw/x11-init.c b/src/cmd/devdraw/x11-init.c
index 4b5b570d..f9cf0868 100644
--- a/src/cmd/devdraw/x11-init.c
+++ b/src/cmd/devdraw/x11-init.c
@@ -733,6 +733,6 @@ _xreplacescreenimage(void)
XFreePixmap(_x.display, _x.nextscreenpm);
_x.nextscreenpm = pixmap;
_x.screenr = r;
- _drawreplacescreenimage(m);
+ gfx_replacescreenimage(m);
return 1;
}
diff --git a/src/cmd/devdraw/x11-itrans.c b/src/cmd/devdraw/x11-itrans.c
index bdf7d2b2..12034d1b 100644
--- a/src/cmd/devdraw/x11-itrans.c
+++ b/src/cmd/devdraw/x11-itrans.c
@@ -146,7 +146,7 @@ abortcompose(void)
static Rune* sendrune(Rune);
-extern int _latin1(Rune*, int);
+extern int latin1(Rune*, int);
static Rune*
xtoplan9latin1(XEvent *e)
{
@@ -182,7 +182,7 @@ sendrune(Rune r)
return nil;
}
k[nk++] = r;
- n = _latin1(k, nk);
+ n = latin1(k, nk);
if(n > 0){
alting = 0;
k[0] = n;
diff --git a/src/cmd/devdraw/x11-srv.c b/src/cmd/devdraw/x11-srv.c
index 4d72415b..cfede6f5 100644
--- a/src/cmd/devdraw/x11-srv.c
+++ b/src/cmd/devdraw/x11-srv.c
@@ -365,7 +365,7 @@ runmsg(Wsysmsg *m)
n = m->count;
if(n > sizeof buf)
n = sizeof buf;
- n = _drawmsgread(buf, n);
+ n = draw_dataread(buf, n);
if(n < 0)
replyerror(m);
else{
@@ -376,7 +376,7 @@ runmsg(Wsysmsg *m)
break;
case Twrdraw:
- if(_drawmsgwrite(m->data, m->count) < 0)
+ if(draw_datawrite(m->data, m->count) < 0)
replyerror(m);
else
replymsg(m);