Lots of X fixes.

This commit is contained in:
rsc 2003-10-11 02:47:43 +00:00
parent 4af386f434
commit 161060a463
14 changed files with 237 additions and 31 deletions

View file

@ -99,6 +99,7 @@ OFILES=\
x11-mouse.$O\
x11-pixelbits.$O\
x11-unload.$O\
x11-wsys.$O\
devdraw.$O\
unix.$O\

View file

@ -167,8 +167,6 @@ drawld2chan[] = {
CMAP8,
};
int log2[] = { -1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 };
u32int
setalpha(u32int color, uchar alpha)
{

View file

@ -138,6 +138,7 @@ void
_initdisplaymemimage(Display *d, Memimage *m)
{
screenimage = m;
m->screenref = 1;
client0 = mallocz(sizeof(Client), 1);
if(client0 == nil){
fprint(2, "initdraw: allocating client0: out of memory");
@ -165,7 +166,16 @@ _drawreplacescreenimage(Memimage *m)
* about the resize through external means, so all we
* need to do is this assignment.
*/
Memimage *om;
qlock(&sdraw.lk);
om = screenimage;
screenimage = m;
m->screenref = 1;
if(om && --om->screenref == 0){
_freememimage(om);
}
qunlock(&sdraw.lk);
}
static
@ -399,6 +409,8 @@ drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
d->name = 0;
d->vers = 0;
d->image = i;
if(i->screenref)
++i->screenref;
d->nfchar = 0;
d->fchar = 0;
d->fromname = 0;
@ -534,11 +546,9 @@ drawfreedimage(DImage *dimage)
drawfreedimage(dimage->fromname);
goto Return;
}
//if(dimage->image == screenimage) /* don't free the display */
// goto Return;
ds = dimage->dscreen;
l = dimage->image;
if(ds){
l = dimage->image;
if(l->data == screenimage->data)
addflush(l->layer->screenr);
if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */
@ -549,8 +559,12 @@ drawfreedimage(DImage *dimage)
else
memlfree(l);
drawfreedscreen(ds);
}else
freememimage(dimage->image);
}else{
if(l->screenref==0)
freememimage(l);
else if(--l->screenref==0)
_freememimage(l);
}
Return:
free(dimage->fchar);
free(dimage);
@ -732,6 +746,7 @@ _drawmsgread(Display *d, void *a, int n)
{
int inbuf;
qlock(&sdraw.lk);
inbuf = d->obufp - d->obuf;
if(n > inbuf)
n = inbuf;
@ -740,6 +755,7 @@ _drawmsgread(Display *d, void *a, int n)
if(inbuf)
memmove(d->obuf, d->obufp-inbuf, inbuf);
d->obufp = d->obuf+inbuf;
qunlock(&sdraw.lk);
return n;
}
@ -776,6 +792,7 @@ _drawmsgwrite(Display *d, void *v, int n)
Refreshfn reffn;
Refx *refx;
qlock(&sdraw.lk);
d->obufp = d->obuf;
a = v;
m = 0;
@ -1516,6 +1533,7 @@ _drawmsgwrite(Display *d, void *v, int n)
continue;
}
}
qunlock(&sdraw.lk);
return oldn - n;
Enodrawimage:
@ -1527,9 +1545,11 @@ Enodrawscreen:
Eshortdraw:
err = "short draw message";
goto error;
/*
Eshortread:
err = "draw read too short";
goto error;
*/
Eimageexists:
err = "image id in use";
goto error;
@ -1551,6 +1571,7 @@ Enotfont:
Eindex:
err = "character index out of range";
goto error;
/*
Enoclient:
err = "no such draw client";
goto error;
@ -1560,6 +1581,7 @@ Edepth:
Enameused:
err = "image name in use";
goto error;
*/
Enoname:
err = "no image with that name";
goto error;
@ -1580,7 +1602,8 @@ Ebadarg:
goto error;
error:
drawerror(display, err);
werrstr("%s", err);
qunlock(&sdraw.lk);
return -1;
}

View file

@ -10,6 +10,7 @@ enum
Arrow3 = 3,
};
/*
static
int
lmin(int a, int b)
@ -18,6 +19,7 @@ lmin(int a, int b)
return a;
return b;
}
*/
static
int

View file

@ -2,6 +2,8 @@
#include <libc.h>
#include <draw.h>
extern vlong _drawflength(int);
Font*
openfont(Display *d, char *name)
{
@ -13,7 +15,7 @@ openfont(Display *d, char *name)
if(fd < 0)
return 0;
n = flength(fd);
n = _drawflength(fd);
buf = malloc(n+1);
if(buf == 0){
close(fd);

View file

@ -29,7 +29,9 @@ subfontname(char *cfname, char *fname, int maxdepth)
if(maxdepth > 8)
maxdepth = 8;
for(i=log2[maxdepth]; i>=0; i--){
for(i=3; i>=0; i--){
if((1<<i) > maxdepth)
continue;
/* try i-bit grey */
snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
if(access(tmp2, AREAD) == 0)

View file

@ -5,7 +5,7 @@
#include <draw.h>
vlong
flength(int fd)
_drawflength(int fd)
{
struct stat s;

View file

@ -37,20 +37,21 @@ xallocmemimage(Rectangle r, u32int chan, int pixmap)
}
/*
* Allocate backing store. What we call a 32-bit image
* the X server calls a 24-bit image.
* Allocate backing store.
*/
d = m->depth;
if(chan == GREY1)
d = 1;
else
d = _x.depth;
if(pixmap != PMundef)
xm->pixmap = pixmap;
else
xm->pixmap = XCreatePixmap(_x.display, _x.drawable,
Dx(r), Dy(r), d==32 ? 24 : d);
xm->pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), d);
/*
* We want to align pixels on word boundaries.
*/
if(d == 24)
if(m->depth == 24)
offset = r.min.x&3;
else
offset = r.min.x&(31/m->depth);
@ -60,7 +61,7 @@ xallocmemimage(Rectangle r, u32int chan, int pixmap)
/*
* Wrap our data in an XImage structure.
*/
xi = XCreateImage(_x.display, _x.vis, d==32 ? 24 : d,
xi = XCreateImage(_x.display, _x.vis, d,
ZPixmap, 0, (char*)m->data->bdata, Dx(r), Dy(r),
32, m->width*sizeof(u32int));
if(xi == nil){

View file

@ -17,7 +17,6 @@ void
memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp,
Memimage *mask, Point mp, int op)
{
int drew;
Memdrawparam *par;
if((par = _memimagedrawsetup(dst, r, src, sp, mask, mp, op)) == nil)
@ -116,6 +115,7 @@ xdraw(Memdrawparam *par)
}
}else{
/* this doesn't work on rob's mac? */
return 0;
gc = _x.gcsimplesrc;
if(dst->chan == CMAP8 && _x.usetable)
sdval = _x.tox11[sdval];

View file

@ -71,7 +71,7 @@ getimage0(Display *d)
fprint(2, "cannot read screen info: %r\n");
abort();
}
n = _drawmsgread(d, info, sizeof info);
if(n != 12*12){
fprint(2, "short screen info\n");
@ -113,8 +113,8 @@ xerror(XDisplay *d, XErrorEvent *e)
{
char buf[200];
print("X error: error_code=%d, request_code=%d, minor=%d\n",
e->error_code, e->request_code, e->minor_code);
print("X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
e->error_code, e->request_code, e->minor_code, d);
XGetErrorText(d, e->error_code, buf, sizeof buf);
print("%s\n", buf);
return 0;
@ -179,6 +179,13 @@ xattach(char *label)
_x.usetable = 1;
}
else
if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
|| XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
_x.vis = xvi.visual;
_x.depth = 15;
_x.usetable = 1;
}
else
if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
|| XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
_x.vis = xvi.visual;
@ -227,6 +234,9 @@ xattach(char *label)
case 8:
_x.chan = CMAP8;
break;
case 15:
_x.chan = RGB15;
break;
case 16: /* how to tell RGB15? */
_x.chan = RGB16;
break;
@ -264,7 +274,7 @@ xattach(char *label)
memset(&attr, 0, sizeof attr);
attr.colormap = _x.cmap;
attr.background_pixel = 0;
attr.background_pixel = ~0;
attr.border_pixel = 0;
_x.drawable = XCreateWindow(
_x.display, /* display */
@ -274,7 +284,7 @@ xattach(char *label)
Dx(r), /* width */
Dy(r), /* height */
0, /* border width */
_x.depth, /* depth */
DefaultDepthOfScreen(xscreen), /* depth */
InputOutput, /* class */
_x.vis, /* visual */
/* valuemask */
@ -328,6 +338,7 @@ xattach(char *label)
*/
_x.screenr = r;
_x.screenpm = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
_x.nextscreenpm = _x.screenpm;
_x.screenimage = xallocmemimage(r, _x.chan, _x.screenpm);
/*
@ -354,18 +365,22 @@ xattach(char *label)
XFlush(_x.display);
/*
* Lots of display connections for various threads.
* Lots of display connections for various procs.
*/
_x.kbdcon = XOpenDisplay(NULL);
_x.mousecon = XOpenDisplay(NULL);
_x.snarfcon = XOpenDisplay(NULL);
if(0) fprint(2, "x: display=%p kbd=%p mouse=%p snarf=%p\n",
_x.display, _x.kbdcon, _x.mousecon, _x.snarfcon);
_x.black = xscreen->black_pixel;
_x.white = xscreen->white_pixel;
return _x.screenimage;
err0:
fprint(2, "%r\n");
/*
* Should do a better job of cleaning up here.
*/
@ -551,6 +566,14 @@ setupcmap(XWindow w)
void
flushmemscreen(Rectangle r)
{
if(_x.nextscreenpm != _x.screenpm){
qlock(&_x.screenlock);
XSync(_x.display, False);
XFreePixmap(_x.display, _x.screenpm);
_x.screenpm = _x.nextscreenpm;
qunlock(&_x.screenlock);
}
if(r.min.x >= r.max.x || r.min.y >= r.max.y)
return;
XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
@ -564,6 +587,11 @@ xexpose(XEvent *e, XDisplay *xd)
XExposeEvent *xe;
Rectangle r;
qlock(&_x.screenlock);
if(_x.screenpm != _x.nextscreenpm){
qunlock(&_x.screenlock);
return;
}
xe = (XExposeEvent*)e;
r.min.x = xe->x;
r.min.y = xe->y;
@ -571,17 +599,29 @@ xexpose(XEvent *e, XDisplay *xd)
r.max.y = xe->y+xe->height;
XCopyArea(xd, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
Dx(r), Dy(r), r.min.x, r.min.y);
XFlush(xd);
XSync(xd, False);
qunlock(&_x.screenlock);
}
int
xconfigure(XEvent *e, XDisplay *xd)
{
Rectangle r;
XConfigureEvent *xe = (XConfigureEvent*)e;
if(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr))
return 0;
_x.newscreenr = Rect(0, 0, xe->width, xe->height);
if(xe->width==0 || xe->height==0)
fprint(2, "ignoring resize to %dx%d\n", xe->width, xe->height);
r = Rect(0, 0, xe->width, xe->height);
qlock(&_x.screenlock);
if(_x.screenpm != _x.nextscreenpm){
XCopyArea(xd, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
Dx(r), Dy(r), r.min.x, r.min.y);
XSync(xd, False);
}
qunlock(&_x.screenlock);
_x.newscreenr = r;
return 1;
}
@ -598,7 +638,9 @@ xreplacescreenimage(void)
pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
m = xallocmemimage(r, _x.chan, pixmap);
_x.screenpm = pixmap;
if(_x.nextscreenpm != _x.screenpm)
XFreePixmap(_x.display, _x.nextscreenpm);
_x.nextscreenpm = pixmap;
_x.screenr = r;
_drawreplacescreenimage(m);
return 1;

View file

@ -256,3 +256,129 @@ xsetcursor(Cursor *c)
XFlush(_x.display);
}
struct {
char buf[SnarfSize];
QLock lk;
} clip;
char*
xgetsnarf(XDisplay *xd)
{
uchar *data, *xdata;
Atom type;
ulong len, lastlen, dummy;
int fmt, i;
XWindow w;
qlock(&clip.lk);
w = XGetSelectionOwner(xd, XA_PRIMARY);
if(w == _x.drawable){
data = (uchar*)strdup(clip.buf);
goto out;
}
if(w == None){
data = nil;
goto out;
}
/*
* We should be waiting for SelectionNotify here, but it might never
* come, and we have no way to time out. Instead, we will zero the
* property, request our buddy to fill it in for us, and wait until
* he's done.
*/
XChangeProperty(xd, _x.drawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
XConvertSelection(xd, XA_PRIMARY, XA_STRING, None, _x.drawable, CurrentTime);
XFlush(xd);
lastlen = 0;
for(i=0; i<30; i++){
usleep(100*1000);
XGetWindowProperty(xd, _x.drawable, XA_STRING, 0, 0, 0, AnyPropertyType,
&type, &fmt, &dummy, &len, &data);
if(lastlen == len && len > 0)
break;
lastlen = len;
}
if(i == 30){
data = nil;
goto out;
}
/* get the property */
data = nil;
XGetWindowProperty(xd, _x.drawable, XA_STRING, 0, SnarfSize/4, 0,
AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
if(type != XA_STRING || len == 0){
if(xdata)
XFree(xdata);
data = nil;
}else{
if(xdata){
data = strdup((char*)xdata);
XFree(xdata);
}else
data = nil;
}
out:
qunlock(&clip.lk);
return data;
}
void
xputsnarf(XDisplay *xd, char *data)
{
if(strlen(data) >= SnarfSize)
return;
qlock(&clip.lk);
strcpy(clip.buf, data);
/*
* BUG: This is wrong. Instead, we should send an event to the
* mouse connection telling it to call XSetSelectionOwner.
*/
XSetSelectionOwner(_x.mousecon, XA_PRIMARY, _x.drawable, CurrentTime);
XFlush(xd);
qunlock(&clip.lk);
}
int
xselect(XEvent *e, XDisplay *xd)
{
XEvent r;
XSelectionRequestEvent *xe;
memset(&r, 0, sizeof r);
xe = (XSelectionRequestEvent*)e;
if(1 || xe->target == XA_STRING){
qlock(&clip.lk);
XChangeProperty(xd, xe->requestor, xe->property, XA_STRING, 8,
PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)+1);
qunlock(&clip.lk);
r.xselection.property = xe->property;
}else{
fprint(2, "asked for a %d\n", xe->target);
r.xselection.property = None;
}
r.xselection.display = xe->display;
/* r.xselection.property filled above */
r.xselection.target = xe->target;
r.xselection.type = SelectionNotify;
r.xselection.requestor = xe->requestor;
r.xselection.time = xe->time;
r.xselection.send_event = True;
r.xselection.selection = xe->selection;
XSendEvent(xd, xe->requestor, False, 0, &r);
XFlush(xd);
return 0;
}
void
putsnarf(char *data)
{
xputsnarf(_x.snarfcon, data);
}
char*
getsnarf(void)
{
return xgetsnarf(_x.snarfcon);
}

View file

@ -41,8 +41,8 @@ _ioproc(void *arg)
kc = arg;
threadsetname("kbdproc");
kc->pid = getpid();
XSelectInput(_x.kbdcon, _x.drawable, KeyPressMask);
for(;;){
XSelectInput(_x.kbdcon, _x.drawable, KeyPressMask);
XWindowEvent(_x.kbdcon, _x.drawable, KeyPressMask, &xevent);
switch(xevent.type){
case KeyPress:

View file

@ -54,7 +54,9 @@ struct Xprivate {
XDisplay *mousecon;
Rectangle newscreenr;
Memimage* screenimage;
QLock screenlock;
XDrawable screenpm;
XDrawable nextscreenpm;
Rectangle screenr;
XDisplay *snarfcon;
int toplan9[256];
@ -73,11 +75,13 @@ extern void xfillcolor(Memimage*, Rectangle, u32int);
extern void xfreexdata(Memimage*);
extern XImage *xgetxdata(Memimage*, Rectangle);
extern void xputxdata(Memimage*, Rectangle);
extern void _initdisplaymemimage(Display*, Memimage*);
struct Mouse;
extern int xtoplan9mouse(XEvent*, struct Mouse*);
extern int xtoplan9kbd(XEvent*);
extern void xexpose(XEvent*, XDisplay*);
extern int xselect(XEvent*, XDisplay*);
extern int xconfigure(XEvent*, XDisplay*);
extern void flushmemscreen(Rectangle);
extern void xmoveto(Point);

View file

@ -48,6 +48,7 @@ void
_ioproc(void *arg)
{
int one;
ulong mask;
Mouse m;
Mousectl *mc;
XEvent xevent;
@ -57,9 +58,10 @@ _ioproc(void *arg)
threadsetname("mouseproc");
memset(&m, 0, sizeof m);
mc->pid = getpid();
mask = MouseMask|ExposureMask|StructureNotifyMask;
XSelectInput(_x.mousecon, _x.drawable, mask);
for(;;){
XSelectInput(_x.mousecon, _x.drawable, MouseMask|ExposureMask|StructureNotifyMask);
XWindowEvent(_x.mousecon, _x.drawable, MouseMask|ExposureMask|StructureNotifyMask, &xevent);
XNextEvent(_x.mousecon, &xevent);
switch(xevent.type){
case Expose:
xexpose(&xevent, _x.mousecon);
@ -68,6 +70,9 @@ _ioproc(void *arg)
if(xconfigure(&xevent, _x.mousecon))
nbsend(mc->resizec, &one);
continue;
case SelectionRequest:
xselect(&xevent, _x.mousecon);
continue;
case ButtonPress:
case ButtonRelease:
case MotionNotify: