commit 41547af3f614061dd2c94bb52ae118f146925743 from: Russ Cox date: Mon Jan 13 21:46:14 2020 UTC devdraw: more cleanup, clearer locking commit - b1a086dee9bf5846b31323ba2c438f8853a9c87f commit + 41547af3f614061dd2c94bb52ae118f146925743 blob - 77a3f44a2d401940ea3f6bef12c41284acffa6a0 blob + e3040779d1370e6550e1ffb98186f3da8b14023a --- src/cmd/devdraw/devdraw.c +++ src/cmd/devdraw/devdraw.c @@ -14,14 +14,12 @@ #include #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, Rectangl 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, DScre 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, 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 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; } blob - 30586228a15294d002c2b0473ce539ce7c7e8b53 blob + dd7fc8ba1998ca5097d3215a67663977b0dc486b --- src/cmd/devdraw/devdraw.h +++ 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*); +// 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. -int _latin1(Rune*, int); -int parsewinsize(char*, Rectangle*, int*); -int mouseswap(int); - +// 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); -extern Client *client0; +// TODO: rpc_flush is called from draw_datawrite, +// which holds c->drawlk. Is this OK? +void rpc_flush(Client*, Rectangle); -void servep9p(Client*); +// 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*); + blob - 2fa9e29d26cf44f6868e112bb1a73bf2cfdaddb8 blob + a3d13a088614807c4c742261dff5aa58a7b94319 --- src/cmd/devdraw/latin1.c +++ 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; blob - d756d3d750069a17b029ae73a10f36022f0a196d blob + 2ce6bb34b42338bcd54366e42757755007339ca8 --- src/cmd/devdraw/mac-screen.m +++ 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; + @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"); -} -// 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 *)validAttributesForMarkedText -{ + +- (NSArray*)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 blob - 0e7540be9b94a460a62c3b07b4c6a412b7ee3861 blob + 5169c11312729a6f7a1ff97b0a3204101176323c --- src/cmd/devdraw/srv.c +++ 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; ikbd.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; } blob - 4b5b570d240b272f51caa10e0ed88a78a2913a3c blob + f9cf0868dce46b69a9b04a7fc295184f4b40d6a4 --- src/cmd/devdraw/x11-init.c +++ 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; } blob - bdf7d2b2e44465fc3f19cbc9a39cfade337a2084 blob + 12034d1b4f312caa163c9bfbe06a734a58d97571 --- src/cmd/devdraw/x11-itrans.c +++ 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; blob - 4d72415b18dd29d1978c44483a06aa3d495f1630 blob + cfede6f5936b216f14af04786b559c40d01193e2 --- src/cmd/devdraw/x11-srv.c +++ 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);