Rewrite X11 snarf. Maybe this will be better.

This commit is contained in:
Russ Cox 2005-10-17 16:18:45 +00:00
parent a43c1e6fab
commit 54ca86f879
3 changed files with 265 additions and 170 deletions

View File

@ -81,7 +81,7 @@ static void xmouse(XEvent*);
static void xkeyboard(XEvent*); static void xkeyboard(XEvent*);
static void xmapping(XEvent*); static void xmapping(XEvent*);
static void xdestroy(XEvent*); static void xdestroy(XEvent*);
static void xselect(XEvent*); static void xselect(XEvent*, Display*);
static void xproc(void*); static void xproc(void*);
static Memimage* xinitscreen(void); static Memimage* xinitscreen(void);
static void initmap(Window); static void initmap(Window);
@ -89,9 +89,9 @@ static GC creategc(Drawable);
static void graphicscmap(XColor*); static void graphicscmap(XColor*);
int xscreendepth; int xscreendepth;
Drawable xscreenid; Drawable xscreenid;
Display* xdisplay; Display* xdisplay; /* used holding draw lock */
Display* xkmcon; Display* xkmcon; /* used only in xproc */
Display* xsnarfcon; Display* xsnarfcon; /* used holding clip.lk */
Visual *xvis; Visual *xvis;
GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc; GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc;
GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0; GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0;
@ -99,6 +99,8 @@ static void graphicscmap(XColor*);
ulong xwhite; ulong xwhite;
ulong xscreenchan; ulong xscreenchan;
static int putsnarf, assertsnarf;
extern Memimage* xallocmemimage(IRectangle, ulong, int); extern Memimage* xallocmemimage(IRectangle, ulong, int);
Memimage *gscreen; Memimage *gscreen;
Screeninfo screen; Screeninfo screen;
@ -134,6 +136,7 @@ attachscreen(IRectangle *r, ulong *chan, int *depth,
void void
flushmemscreen(IRectangle r) flushmemscreen(IRectangle r)
{ {
assert(!drawcanqlock());
if(r.min.x >= r.max.x || r.min.y >= r.max.y) if(r.min.x >= r.max.x || r.min.y >= r.max.y)
return; return;
XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y); XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy, r.min.x, r.min.y, Dx(r), Dy(r), r.min.x, r.min.y);
@ -160,8 +163,10 @@ revbyte(int b)
void void
mouseset(IPoint xy) mouseset(IPoint xy)
{ {
drawqlock();
XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y); XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y);
XFlush(xdisplay); XFlush(xdisplay);
drawqunlock();
} }
static Cursor xcursor; static Cursor xcursor;
@ -180,6 +185,7 @@ setcursor(void)
mask[i] = revbyte(cursor.set[i] | cursor.clr[i]); mask[i] = revbyte(cursor.set[i] | cursor.clr[i]);
} }
drawqlock();
fg = map[0]; fg = map[0];
bg = map[255]; bg = map[255];
xsrc = XCreateBitmapFromData(xdisplay, xdrawable, src, 16, 16); xsrc = XCreateBitmapFromData(xdisplay, xdrawable, src, 16, 16);
@ -194,17 +200,20 @@ setcursor(void)
XFreePixmap(xdisplay, xsrc); XFreePixmap(xdisplay, xsrc);
XFreePixmap(xdisplay, xmask); XFreePixmap(xdisplay, xmask);
XFlush(xdisplay); XFlush(xdisplay);
drawqunlock();
} }
void void
cursorarrow(void) cursorarrow(void)
{ {
drawqlock();
if(xcursor != 0){ if(xcursor != 0){
XFreeCursor(xdisplay, xcursor); XFreeCursor(xdisplay, xcursor);
xcursor = 0; xcursor = 0;
} }
XUndefineCursor(xdisplay, xdrawable); XUndefineCursor(xdisplay, xdrawable);
XFlush(xdisplay); XFlush(xdisplay);
drawqunlock();
} }
static void static void
@ -229,7 +238,7 @@ xproc(void *arg)
for(;;) { for(;;) {
//XWindowEvent(xkmcon, xdrawable, mask, &event); //XWindowEvent(xkmcon, xdrawable, mask, &event);
XNextEvent(xkmcon, &event); XNextEvent(xkmcon, &event);
xselect(&event); xselect(&event, xkmcon);
xkeyboard(&event); xkeyboard(&event);
xmouse(&event); xmouse(&event);
xexpose(&event); xexpose(&event);
@ -624,13 +633,6 @@ xdestroy(XEvent *e)
exit(0); exit(0);
} }
static void
xselection(XEvent *e)
{
XSelectionRequestEvent *xre;
XSelectionEvent *xe;
}
static void static void
xmapping(XEvent *e) xmapping(XEvent *e)
{ {
@ -691,7 +693,7 @@ xkeyboard(XEvent *e)
return; return;
XLookupString(e,NULL,0,&k,NULL); XLookupString((XKeyEvent*)e, NULL, 0, &k, NULL);
if(k == XK_Multi_key || k == NoSymbol) if(k == XK_Multi_key || k == NoSymbol)
return; return;
@ -785,8 +787,10 @@ xkeyboard(XEvent *e)
default: /* not ISO-1 or tty control */ default: /* not ISO-1 or tty control */
if(k>0xff){ if(k>0xff){
k = keysym2ucs(k); /* supplied by X */ k = keysym2ucs(k); /* supplied by X */
if(k == -1) return; if(k == -1)
return;
} }
break;
} }
} }
@ -811,9 +815,27 @@ xmouse(XEvent *e)
XButtonEvent *be; XButtonEvent *be;
XMotionEvent *me; XMotionEvent *me;
if(putsnarf != assertsnarf){
assertsnarf = putsnarf;
XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
if(clipboard != None)
XSetSelectionOwner(xkmcon, clipboard, xdrawable, CurrentTime);
XFlush(xkmcon);
}
switch(e->type){ switch(e->type){
case ButtonPress: case ButtonPress:
be = (XButtonEvent *)e; be = (XButtonEvent *)e;
/*
* Fake message, just sent to make us announce snarf.
* Apparently state and button are 16 and 8 bits on
* the wire, since they are truncated by the time they
* get to us.
*/
if(be->send_event
&& (~be->state&0xFFFF)==0
&& (~be->button&0xFF)==0)
return;
ms.xy.x = be->x; ms.xy.x = be->x;
ms.xy.y = be->y; ms.xy.y = be->y;
s = be->state; s = be->state;
@ -921,154 +943,16 @@ setcolor(ulong i, ulong r, ulong g, ulong b)
/* no-op */ /* no-op */
} }
typedef struct Clip Clip;
struct Clip
{
char buf[SnarfSize];
ulong n;
int want, have;
QLock lk;
Rendez vous;
};
Clip clip;
enum {
Chunk = 2048
};
static void
xselect(XEvent *e)
{
XSelectionRequestEvent *q;
XEvent r;
Atom a[4];
char *name;
if(e->type != SelectionRequest)
return;
/*
* The lock is around the whole routine because we use the
* lock to make sure two people aren't sending on xkmcon
* at once.
*/
q = (XSelectionRequestEvent*)e;
r.xselection.property = q->property;
if(q->target == targets) {
a[0] = XA_STRING;
a[1] = utf8string;
a[2] = text;
a[3] = compoundtext;
XChangeProperty(xkmcon, q->requestor, q->property, q->target,
8, PropModeReplace, (uchar*)a, sizeof a);
}else if(q->target == XA_STRING || q->target == utf8string || q->target == text || q->target == compoundtext){
qlock(&clip.lk);
XChangeProperty(xkmcon, q->requestor, q->property, q->target, 8,
PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
qunlock(&clip.lk);
}else {
name = XGetAtomName(xkmcon, q->target);
if(strcmp(name, "TIMESTAMP") != 0)
fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)q->target);
r.xselection.property = None;
}
r.xselection.type = SelectionNotify;
r.xselection.display = q->display;
r.xselection.requestor = q->requestor;
r.xselection.selection = q->selection;
r.xselection.target = q->target;
r.xselection.time = q->time;
XSendEvent(xkmcon, q->requestor, False, 0, &r);
XFlush(xkmcon);
}
int
haveclip(void *a)
{
return clip.want == clip.have;
}
#undef long /* sic */
char*
clipread(void)
{
Window w;
XEvent e;
Atom type;
unsigned long len, lleft, left, dummy;
int i, fmt, res;
uchar *data;
qlock(&clip.lk);
w = XGetSelectionOwner(xsnarfcon, XA_PRIMARY);
if(w == xdrawable)
data = (uchar*)strdup(clip.buf);
else if(w == None)
data = nil;
else {
/*
* we're supposed to get a notification, but we seem not to,
* so let's just watch and see when the buffer stabilizes.
* if you know how to fix this, mail rsc@plan9.bell-labs.com.
*/
XChangeProperty(xsnarfcon, xdrawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace,
(uchar*)"", 0);
XConvertSelection(xsnarfcon, XA_PRIMARY, XA_STRING, None, xdrawable, CurrentTime);
XFlush(xsnarfcon);
for(i=0; i<30; i++){
osmsleep(100);
XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, 0, 0, AnyPropertyType,
&type, &fmt, &len, &left, &data);
if(lleft == left && left > 0)
break;
lleft = left;
}
if(left > 0){
res = XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, left, 0,
AnyPropertyType, &type, &fmt, &len, &dummy, &data);
data = (uchar*)strdup(data);
}else
data = nil;
}
qunlock(&clip.lk);
return (char*)data;
}
int
clipwrite(char *buf)
{
int n;
n = strlen(buf);
qlock(&clip.lk);
if(n >= SnarfSize)
n = SnarfSize - 1;
memmove(clip.buf, buf, n);
clip.buf[n] = 0;
clip.n = n;
/*
* xkmcon so that we get the event in the select loop.
* It seems to be okay to send a message and read an event
* from a Display* at the same time. Let's hope so.
*/
XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
XFlush(xkmcon);
qunlock(&clip.lk);
return n;
}
#define long int /* sic */
int int
atlocalconsole(void) atlocalconsole(void)
{ {
char *p, *q; char *p, *q;
char buf[128]; char buf[128];
p = getenv("DRAWTERM_ATLOCALCONSOLE");
if(p && atoi(p) == 1)
return 1;
p = getenv("DISPLAY"); p = getenv("DISPLAY");
if(p == nil) if(p == nil)
return 0; return 0;
@ -1092,3 +976,193 @@ atlocalconsole(void)
return 0; return 0;
} }
/*
* Cut and paste. Just couldn't stand to make this simple...
*/
typedef struct Clip Clip;
struct Clip
{
char buf[SnarfSize];
QLock lk;
};
Clip clip;
#undef long /* sic */
#undef ulong
static char*
_xgetsnarf(Display *xd)
{
uchar *data, *xdata;
Atom clipboard, type, prop;
ulong len, lastlen, dummy;
int fmt, i;
Window w;
qlock(&clip.lk);
/*
* Have we snarfed recently and the X server hasn't caught up?
*/
if(putsnarf != assertsnarf)
goto mine;
/*
* Is there a primary selection (highlighted text in an xterm)?
*/
clipboard = XA_PRIMARY;
w = XGetSelectionOwner(xd, XA_PRIMARY);
if(w == xdrawable){
mine:
data = (uchar*)strdup(clip.buf);
goto out;
}
/*
* If not, is there a clipboard selection?
*/
if(w == None && clipboard != None){
clipboard = clipboard;
w = XGetSelectionOwner(xd, clipboard);
if(w == xdrawable)
goto mine;
}
/*
* If not, give up.
*/
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 clear
* local property #1, request our buddy to fill it in for us, and poll
* until he's done or we get tired of waiting.
*
* We should try to go for utf8string instead of XA_STRING,
* but that would add to the polling.
*/
prop = 1;
XChangeProperty(xd, xdrawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
XConvertSelection(xd, clipboard, XA_STRING, prop, xdrawable, CurrentTime);
XFlush(xd);
lastlen = 0;
for(i=0; i<10 || (lastlen!=0 && i<30); i++){
usleep(100*1000);
XGetWindowProperty(xd, xdrawable, prop, 0, 0, 0, AnyPropertyType,
&type, &fmt, &dummy, &len, &data);
if(lastlen == len && len > 0)
break;
lastlen = len;
}
if(i == 10){
data = nil;
goto out;
}
/* get the property */
data = nil;
XGetWindowProperty(xd, xdrawable, prop, 0, SnarfSize/sizeof(ulong), 0,
AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
if((type != XA_STRING && type != utf8string) || len == 0){
if(xdata)
XFree(xdata);
data = nil;
}else{
if(xdata){
data = (uchar*)strdup((char*)xdata);
XFree(xdata);
}else
data = nil;
}
out:
qunlock(&clip.lk);
return (char*)data;
}
static void
_xputsnarf(Display *xd, char *data)
{
XButtonEvent e;
if(strlen(data) >= SnarfSize)
return;
qlock(&clip.lk);
strcpy(clip.buf, data);
/* leave note for mouse proc to assert selection ownership */
putsnarf++;
/* send mouse a fake event so snarf is announced */
memset(&e, 0, sizeof e);
e.type = ButtonPress;
e.window = xdrawable;
e.state = ~0;
e.button = ~0;
XSendEvent(xd, xdrawable, True, ButtonPressMask, (XEvent*)&e);
XFlush(xd);
qunlock(&clip.lk);
}
static void
xselect(XEvent *e, Display *xd)
{
char *name;
XEvent r;
XSelectionRequestEvent *xe;
Atom a[4];
memset(&r, 0, sizeof r);
xe = (XSelectionRequestEvent*)e;
if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n",
xe->target, xe->requestor, xe->property, xe->selection);
r.xselection.property = xe->property;
if(xe->target == targets){
a[0] = XA_STRING;
a[1] = utf8string;
a[2] = text;
a[3] = compoundtext;
XChangeProperty(xd, xe->requestor, xe->property, xe->target,
8, PropModeReplace, (uchar*)a, sizeof a);
}else if(xe->target == XA_STRING || xe->target == utf8string || xe->target == text || xe->target == compoundtext){
/* if the target is STRING we're supposed to reply with Latin1 XXX */
qlock(&clip.lk);
XChangeProperty(xd, xe->requestor, xe->property, xe->target,
8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
qunlock(&clip.lk);
}else{
name = XGetAtomName(xd, xe->target);
if(strcmp(name, "TIMESTAMP") != 0)
fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)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);
}
char*
clipread(void)
{
return _xgetsnarf(xsnarfcon);
}
int
clipwrite(char *buf)
{
_xputsnarf(xsnarfcon, buf);
return 0;
}

View File

@ -183,6 +183,24 @@ static char Eoldname[] = "named image no longer valid";
static char Enamed[] = "image already has name"; static char Enamed[] = "image already has name";
static char Ewrongname[] = "wrong name for image"; static char Ewrongname[] = "wrong name for image";
int
drawcanqlock(void)
{
return canqlock(&sdraw.lk);
}
void
drawqlock(void)
{
qlock(&sdraw.lk);
}
void
drawqunlock(void)
{
qunlock(&sdraw.lk);
}
static int static int
drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp) drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp)
{ {

View File

@ -79,6 +79,9 @@ Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*);
int devwstat(Chan*, uchar*, int); int devwstat(Chan*, uchar*, int);
void drawactive(int); void drawactive(int);
void drawcmap(void); void drawcmap(void);
int drawcanqlock(void);
void drawqlock(void);
void drawqunlock(void);
void dumpaproc(Proc*); void dumpaproc(Proc*);
void dumpqueues(void); void dumpqueues(void);
void dumpregs(Ureg*); void dumpregs(Ureg*);