History

Rewrite X11 snarf. Maybe this will be better.

Russ Cox committed 21 years ago

Commit 54ca86f1 parent a43c1e63 files · +256 −161Browse files

Unified · Split

3 files
  1. gui-x11/screen.c +235 −161
  2. kern/devdraw.c +18 −0
  3. kern/fns.h +3 −0
gui-x11/screen.c+235−161
@@ -16,9 +16,9 @@ · 15 unmodified lines
1616 */
1717 #define Point IPoint
1818 #define Rectangle IRectangle
19−#define Display IDisplay
20−#define Font IFont
21−#define Screen IScreen
19+#define Display IDisplay
20+#define Font IFont
21+#define Screen IScreen
2222
2323 #include <u.h>
2424 #include <libc.h>
@@ -81,7 +81,7 @@ static void xmouse(XEvent*); · 56 unmodified lines
8181 static void xkeyboard(XEvent*);
8282 static void xmapping(XEvent*);
8383 static void xdestroy(XEvent*);
84−static void xselect(XEvent*);
84+static void xselect(XEvent*, Display*);
8585 static void xproc(void*);
8686 static Memimage* xinitscreen(void);
8787 static void initmap(Window);
@@ -89,16 +89,18 @@ static GC creategc(Drawable); · 1 unmodified line
8989 static void graphicscmap(XColor*);
9090 int xscreendepth;
9191 Drawable xscreenid;
92− Display* xdisplay;
93− Display* xkmcon;
94− Display* xsnarfcon;
92+ Display* xdisplay; /* used holding draw lock */
93+ Display* xkmcon; /* used only in xproc */
94+ Display* xsnarfcon; /* used holding clip.lk */
9595 Visual *xvis;
9696 GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc;
9797 GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0;
9898 ulong xblack;
9999 ulong xwhite;
100100 ulong xscreenchan;
101−
101+
102+static int putsnarf, assertsnarf;
103+
102104 extern Memimage* xallocmemimage(IRectangle, ulong, int);
103105 Memimage *gscreen;
104106 Screeninfo screen;
@@ -134,6 +136,7 @@ attachscreen(IRectangle *r, ulong *chan, int *depth, · 29 unmodified lines
134136 void
135137 flushmemscreen(IRectangle r)
136138 {
139+ assert(!drawcanqlock());
137140 if(r.min.x >= r.max.x || r.min.y >= r.max.y)
138141 return;
139142 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) · 20 unmodified lines
160163 void
161164 mouseset(IPoint xy)
162165 {
166+ drawqlock();
163167 XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y);
164168 XFlush(xdisplay);
169+ drawqunlock();
165170 }
166171
167172 static Cursor xcursor;
@@ -180,6 +185,7 @@ setcursor(void) · 12 unmodified lines
180185 mask[i] = revbyte(cursor.set[i] | cursor.clr[i]);
181186 }
182187
188+ drawqlock();
183189 fg = map[0];
184190 bg = map[255];
185191 xsrc = XCreateBitmapFromData(xdisplay, xdrawable, src, 16, 16);
@@ -194,17 +200,20 @@ setcursor(void) · 8 unmodified lines
194200 XFreePixmap(xdisplay, xsrc);
195201 XFreePixmap(xdisplay, xmask);
196202 XFlush(xdisplay);
203+ drawqunlock();
197204 }
198205
199206 void
200207 cursorarrow(void)
201208 {
209+ drawqlock();
202210 if(xcursor != 0){
203211 XFreeCursor(xdisplay, xcursor);
204212 xcursor = 0;
205213 }
206214 XUndefineCursor(xdisplay, xdrawable);
207215 XFlush(xdisplay);
216+ drawqunlock();
208217 }
209218
210219 static void
@@ -229,7 +238,7 @@ xproc(void *arg) · 18 unmodified lines
229238 for(;;) {
230239 //XWindowEvent(xkmcon, xdrawable, mask, &event);
231240 XNextEvent(xkmcon, &event);
232− xselect(&event);
241+ xselect(&event, xkmcon);
233242 xkeyboard(&event);
234243 xmouse(&event);
235244 xexpose(&event);
@@ -464,11 +473,11 @@ xinitscreen(void) · 228 unmodified lines
464473 exit(0);
465474 }
466475
467− clipboard = XInternAtom(xkmcon, "CLIPBOARD", False);
468− utf8string = XInternAtom(xkmcon, "UTF8_STRING", False);
469− targets = XInternAtom(xkmcon, "TARGETS", False);
470− text = XInternAtom(xkmcon, "TEXT", False);
471− compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False);
476+ clipboard = XInternAtom(xkmcon, "CLIPBOARD", False);
477+ utf8string = XInternAtom(xkmcon, "UTF8_STRING", False);
478+ targets = XInternAtom(xkmcon, "TARGETS", False);
479+ text = XInternAtom(xkmcon, "TEXT", False);
480+ compoundtext = XInternAtom(xkmcon, "COMPOUND_TEXT", False);
472481
473482 xblack = screen->black_pixel;
474483 xwhite = screen->white_pixel;
@@ -624,13 +633,6 @@ xdestroy(XEvent *e) · 149 unmodified lines
624633 exit(0);
625634 }
626635
627−static void
628−xselection(XEvent *e)
629−{
630− XSelectionRequestEvent *xre;
631− XSelectionEvent *xe;
632−}
633−
634636 static void
635637 xmapping(XEvent *e)
636638 {
@@ -691,7 +693,7 @@ xkeyboard(XEvent *e) · 54 unmodified lines
691693 return;
692694
693695
694− XLookupString(e,NULL,0,&k,NULL);
696+ XLookupString((XKeyEvent*)e, NULL, 0, &k, NULL);
695697
696698 if(k == XK_Multi_key || k == NoSymbol)
697699 return;
@@ -781,12 +783,14 @@ xkeyboard(XEvent *e) · 83 unmodified lines
781783 case XK_Super_R:
782784 case XK_Hyper_L:
783785 case XK_Hyper_R:
784− return;
786+ return;
785787 default: /* not ISO-1 or tty control */
786− if(k>0xff) {
787− k = keysym2ucs(k); /* supplied by X */
788− if(k == -1) return;
789− }
788+ if(k>0xff){
789+ k = keysym2ucs(k); /* supplied by X */
790+ if(k == -1)
791+ return;
792+ }
793+ break;
790794 }
791795 }
792796
@@ -811,9 +815,27 @@ xmouse(XEvent *e) · 18 unmodified lines
811815 XButtonEvent *be;
812816 XMotionEvent *me;
813817
818+ if(putsnarf != assertsnarf){
819+ assertsnarf = putsnarf;
820+ XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
821+ if(clipboard != None)
822+ XSetSelectionOwner(xkmcon, clipboard, xdrawable, CurrentTime);
823+ XFlush(xkmcon);
824+ }
825+
814826 switch(e->type){
815827 case ButtonPress:
816828 be = (XButtonEvent *)e;
829+ /*
830+ * Fake message, just sent to make us announce snarf.
831+ * Apparently state and button are 16 and 8 bits on
832+ * the wire, since they are truncated by the time they
833+ * get to us.
834+ */
835+ if(be->send_event
836+ && (~be->state&0xFFFF)==0
837+ && (~be->button&0xFF)==0)
838+ return;
817839 ms.xy.x = be->x;
818840 ms.xy.y = be->y;
819841 s = be->state;
@@ -921,174 +943,226 @@ setcolor(ulong i, ulong r, ulong g, ulong b) · 101 unmodified lines
921943 /* no-op */
922944 }
923945
924−typedef struct Clip Clip;
925−struct Clip
946+int
947+atlocalconsole(void)
926948 {
927− char buf[SnarfSize];
928− ulong n;
929− int want, have;
930− QLock lk;
931− Rendez vous;
932−};
933−
934−Clip clip;
949+ char *p, *q;
950+ char buf[128];
935951
936−enum {
937− Chunk = 2048
938−};
952+ p = getenv("DRAWTERM_ATLOCALCONSOLE");
953+ if(p && atoi(p) == 1)
954+ return 1;
939955
940−static void
941−xselect(XEvent *e)
942−{
943− XSelectionRequestEvent *q;
944− XEvent r;
945− Atom a[4];
946− char *name;
956+ p = getenv("DISPLAY");
957+ if(p == nil)
958+ return 0;
947959
960+ /* extract host part */
961+ q = strchr(p, ':');
962+ if(q == nil)
963+ return 0;
964+ *q = 0;
948965
949− if(e->type != SelectionRequest)
950− return;
966+ if(strcmp(p, "") == 0)
967+ return 1;
951968
952− /*
953− * The lock is around the whole routine because we use the
954− * lock to make sure two people aren't sending on xkmcon
955− * at once.
956− */
957− q = (XSelectionRequestEvent*)e;
958−
959− r.xselection.property = q->property;
960− if(q->target == targets) {
961− a[0] = XA_STRING;
962− a[1] = utf8string;
963− a[2] = text;
964− a[3] = compoundtext;
965−
966− XChangeProperty(xkmcon, q->requestor, q->property, q->target,
967− 8, PropModeReplace, (uchar*)a, sizeof a);
968− }else if(q->target == XA_STRING || q->target == utf8string || q->target == text || q->target == compoundtext){
969− qlock(&clip.lk);
970− XChangeProperty(xkmcon, q->requestor, q->property, q->target, 8,
971− PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
972− qunlock(&clip.lk);
973− }else {
974− name = XGetAtomName(xkmcon, q->target);
975− if(strcmp(name, "TIMESTAMP") != 0)
976− fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)q->target);
977− r.xselection.property = None;
969+ /* try to match against system name (i.e. for ssh) */
970+ if(gethostname(buf, sizeof buf) == 0){
971+ if(strcmp(p, buf) == 0)
972+ return 1;
973+ if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.')
974+ return 1;
978975 }
979−
980− r.xselection.type = SelectionNotify;
981− r.xselection.display = q->display;
982− r.xselection.requestor = q->requestor;
983− r.xselection.selection = q->selection;
984− r.xselection.target = q->target;
985− r.xselection.time = q->time;
986− XSendEvent(xkmcon, q->requestor, False, 0, &r);
987− XFlush(xkmcon);
976+
977+ return 0;
988978 }
989979
990−int
991−haveclip(void *a)
980+/*
981+ * Cut and paste. Just couldn't stand to make this simple...
982+ */
983+
984+typedef struct Clip Clip;
985+struct Clip
992986 {
993− return clip.want == clip.have;
994−}
987+ char buf[SnarfSize];
988+ QLock lk;
989+};
990+Clip clip;
995991
996−#undef long /* sic */
997−char*
998−clipread(void)
992+#undef long /* sic */
993+#undef ulong
994+
995+static char*
996+_xgetsnarf(Display *xd)
999997 {
998+ uchar *data, *xdata;
999+ Atom clipboard, type, prop;
1000+ ulong len, lastlen, dummy;
1001+ int fmt, i;
10001002 Window w;
1001− XEvent e;
1002− Atom type;
1003− unsigned long len, lleft, left, dummy;
1004− int i, fmt, res;
1005− uchar *data;
10061003
10071004 qlock(&clip.lk);
1008− w = XGetSelectionOwner(xsnarfcon, XA_PRIMARY);
1009− if(w == xdrawable)
1005+ /*
1006+ * Have we snarfed recently and the X server hasn't caught up?
1007+ */
1008+ if(putsnarf != assertsnarf)
1009+ goto mine;
1010+
1011+ /*
1012+ * Is there a primary selection (highlighted text in an xterm)?
1013+ */
1014+ clipboard = XA_PRIMARY;
1015+ w = XGetSelectionOwner(xd, XA_PRIMARY);
1016+ if(w == xdrawable){
1017+ mine:
10101018 data = (uchar*)strdup(clip.buf);
1011− else if(w == None)
1019+ goto out;
1020+ }
1021+
1022+ /*
1023+ * If not, is there a clipboard selection?
1024+ */
1025+ if(w == None && clipboard != None){
1026+ clipboard = clipboard;
1027+ w = XGetSelectionOwner(xd, clipboard);
1028+ if(w == xdrawable)
1029+ goto mine;
1030+ }
1031+
1032+ /*
1033+ * If not, give up.
1034+ */
1035+ if(w == None){
10121036 data = nil;
1013− else {
1014− /*
1015− * we're supposed to get a notification, but we seem not to,
1016− * so let's just watch and see when the buffer stabilizes.
1017− * if you know how to fix this, mail rsc@plan9.bell-labs.com.
1018− */
1019− XChangeProperty(xsnarfcon, xdrawable, XA_PRIMARY, XA_STRING, 8, PropModeReplace,
1020− (uchar*)"", 0);
1021− XConvertSelection(xsnarfcon, XA_PRIMARY, XA_STRING, None, xdrawable, CurrentTime);
1022− XFlush(xsnarfcon);
1023− for(i=0; i<30; i++){
1024− osmsleep(100);
1025− XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, 0, 0, AnyPropertyType,
1026− &type, &fmt, &len, &left, &data);
1027− if(lleft == left && left > 0)
1028− break;
1029− lleft = left;
1030− }
1031− if(left > 0){
1032− res = XGetWindowProperty(xsnarfcon, xdrawable, XA_STRING, 0, left, 0,
1033− AnyPropertyType, &type, &fmt, &len, &dummy, &data);
1034− data = (uchar*)strdup(data);
1037+ goto out;
1038+ }
1039+
1040+ /*
1041+ * We should be waiting for SelectionNotify here, but it might never
1042+ * come, and we have no way to time out. Instead, we will clear
1043+ * local property #1, request our buddy to fill it in for us, and poll
1044+ * until he's done or we get tired of waiting.
1045+ *
1046+ * We should try to go for utf8string instead of XA_STRING,
1047+ * but that would add to the polling.
1048+ */
1049+ prop = 1;
1050+ XChangeProperty(xd, xdrawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
1051+ XConvertSelection(xd, clipboard, XA_STRING, prop, xdrawable, CurrentTime);
1052+ XFlush(xd);
1053+ lastlen = 0;
1054+ for(i=0; i<10 || (lastlen!=0 && i<30); i++){
1055+ usleep(100*1000);
1056+ XGetWindowProperty(xd, xdrawable, prop, 0, 0, 0, AnyPropertyType,
1057+ &type, &fmt, &dummy, &len, &data);
1058+ if(lastlen == len && len > 0)
1059+ break;
1060+ lastlen = len;
1061+ }
1062+ if(i == 10){
1063+ data = nil;
1064+ goto out;
1065+ }
1066+ /* get the property */
1067+ data = nil;
1068+ XGetWindowProperty(xd, xdrawable, prop, 0, SnarfSize/sizeof(ulong), 0,
1069+ AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
1070+ if((type != XA_STRING && type != utf8string) || len == 0){
1071+ if(xdata)
1072+ XFree(xdata);
1073+ data = nil;
1074+ }else{
1075+ if(xdata){
1076+ data = (uchar*)strdup((char*)xdata);
1077+ XFree(xdata);
10351078 }else
10361079 data = nil;
10371080 }
1081+out:
10381082 qunlock(&clip.lk);
10391083 return (char*)data;
10401084 }
10411085
1042−int
1043−clipwrite(char *buf)
1086+static void
1087+_xputsnarf(Display *xd, char *data)
10441088 {
1045− int n;
1089+ XButtonEvent e;
10461090
1047− n = strlen(buf);
1091+ if(strlen(data) >= SnarfSize)
1092+ return;
10481093 qlock(&clip.lk);
1049− if(n >= SnarfSize)
1050− n = SnarfSize - 1;
1051− memmove(clip.buf, buf, n);
1052− clip.buf[n] = 0;
1053− clip.n = n;
1054− /*
1055− * xkmcon so that we get the event in the select loop.
1056− * It seems to be okay to send a message and read an event
1057− * from a Display* at the same time. Let's hope so.
1058− */
1059− XSetSelectionOwner(xkmcon, XA_PRIMARY, xdrawable, CurrentTime);
1060− XFlush(xkmcon);
1094+ strcpy(clip.buf, data);
1095+
1096+ /* leave note for mouse proc to assert selection ownership */
1097+ putsnarf++;
1098+
1099+ /* send mouse a fake event so snarf is announced */
1100+ memset(&e, 0, sizeof e);
1101+ e.type = ButtonPress;
1102+ e.window = xdrawable;
1103+ e.state = ~0;
1104+ e.button = ~0;
1105+ XSendEvent(xd, xdrawable, True, ButtonPressMask, (XEvent*)&e);
1106+ XFlush(xd);
10611107 qunlock(&clip.lk);
1062− return n;
10631108 }
1064−#define long int /* sic */
10651109
1066−int
1067−atlocalconsole(void)
1110+static void
1111+xselect(XEvent *e, Display *xd)
10681112 {
1069− char *p, *q;
1070− char buf[128];
1113+ char *name;
1114+ XEvent r;
1115+ XSelectionRequestEvent *xe;
1116+ Atom a[4];
10711117
1072− p = getenv("DISPLAY");
1073− if(p == nil)
1074− return 0;
1118+ memset(&r, 0, sizeof r);
1119+ xe = (XSelectionRequestEvent*)e;
1120+if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n",
1121+ xe->target, xe->requestor, xe->property, xe->selection);
1122+ r.xselection.property = xe->property;
1123+ if(xe->target == targets){
1124+ a[0] = XA_STRING;
1125+ a[1] = utf8string;
1126+ a[2] = text;
1127+ a[3] = compoundtext;
1128+
1129+ XChangeProperty(xd, xe->requestor, xe->property, xe->target,
1130+ 8, PropModeReplace, (uchar*)a, sizeof a);
1131+ }else if(xe->target == XA_STRING || xe->target == utf8string || xe->target == text || xe->target == compoundtext){
1132+ /* if the target is STRING we're supposed to reply with Latin1 XXX */
1133+ qlock(&clip.lk);
1134+ XChangeProperty(xd, xe->requestor, xe->property, xe->target,
1135+ 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
1136+ qunlock(&clip.lk);
1137+ }else{
1138+ name = XGetAtomName(xd, xe->target);
1139+ if(strcmp(name, "TIMESTAMP") != 0)
1140+ fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
1141+ r.xselection.property = None;
1142+ }
10751143
1076− /* extract host part */
1077− q = strchr(p, ':');
1078− if(q == nil)
1079− return 0;
1080− *q = 0;
1144+ r.xselection.display = xe->display;
1145+ /* r.xselection.property filled above */
1146+ r.xselection.target = xe->target;
1147+ r.xselection.type = SelectionNotify;
1148+ r.xselection.requestor = xe->requestor;
1149+ r.xselection.time = xe->time;
1150+ r.xselection.send_event = True;
1151+ r.xselection.selection = xe->selection;
1152+ XSendEvent(xd, xe->requestor, False, 0, &r);
1153+ XFlush(xd);
1154+}
10811155
1082− if(strcmp(p, "") == 0)
1083− return 1;
1156+char*
1157+clipread(void)
1158+{
1159+ return _xgetsnarf(xsnarfcon);
1160+}
10841161
1085− /* try to match against system name (i.e. for ssh) */
1086− if(gethostname(buf, sizeof buf) == 0){
1087− if(strcmp(p, buf) == 0)
1088− return 1;
1089− if(strncmp(p, buf, strlen(p)) == 0 && buf[strlen(p)]=='.')
1090− return 1;
1091− }
1092−
1162+int
1163+clipwrite(char *buf)
1164+{
1165+ _xputsnarf(xsnarfcon, buf);
10931166 return 0;
10941167 }
1168+
kern/devdraw.c+18−0
@@ -183,6 +183,24 @@ static char Eoldname[] = "named image no longer valid"; · 182 unmodified lines
183183 static char Enamed[] = "image already has name";
184184 static char Ewrongname[] = "wrong name for image";
185185
186+int
187+drawcanqlock(void)
188+{
189+ return canqlock(&sdraw.lk);
190+}
191+
192+void
193+drawqlock(void)
194+{
195+ qlock(&sdraw.lk);
196+}
197+
198+void
199+drawqunlock(void)
200+{
201+ qunlock(&sdraw.lk);
202+}
203+
186204 static int
187205 drawgen(Chan *c, char *name, Dirtab *dt, int ndt, int s, Dir *dp)
188206 {
kern/fns.h+3−0
@@ -79,6 +79,9 @@ Walkqid* devwalk(Chan*, Chan*, char**, int, Dirtab*, int, Devgen*); · 78 unmodified lines
7979 int devwstat(Chan*, uchar*, int);
8080 void drawactive(int);
8181 void drawcmap(void);
82+int drawcanqlock(void);
83+void drawqlock(void);
84+void drawqunlock(void);
8285 void dumpaproc(Proc*);
8386 void dumpqueues(void);
8487 void dumpregs(Ureg*);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t