| @@ -16,9 +16,9 @@ · 15 unmodified lines |
| 16 | 16 | */ |
| 17 | 17 | #define Point IPoint |
| 18 | 18 | #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 |
| 22 | 22 | |
| 23 | 23 | #include <u.h> |
| 24 | 24 | #include <libc.h> |
| @@ -81,7 +81,7 @@ static void xmouse(XEvent*); · 56 unmodified lines |
| 81 | 81 | static void xkeyboard(XEvent*); |
| 82 | 82 | static void xmapping(XEvent*); |
| 83 | 83 | static void xdestroy(XEvent*); |
| 84 | | −static void xselect(XEvent*); |
| 84 | +static void xselect(XEvent*, Display*); |
| 85 | 85 | static void xproc(void*); |
| 86 | 86 | static Memimage* xinitscreen(void); |
| 87 | 87 | static void initmap(Window); |
| @@ -89,16 +89,18 @@ static GC creategc(Drawable); · 1 unmodified line |
| 89 | 89 | static void graphicscmap(XColor*); |
| 90 | 90 | int xscreendepth; |
| 91 | 91 | 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 */ |
| 95 | 95 | Visual *xvis; |
| 96 | 96 | GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc; |
| 97 | 97 | GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0; |
| 98 | 98 | ulong xblack; |
| 99 | 99 | ulong xwhite; |
| 100 | 100 | ulong xscreenchan; |
| 101 | | − |
| 101 | + |
| 102 | +static int putsnarf, assertsnarf; |
| 103 | + |
| 102 | 104 | extern Memimage* xallocmemimage(IRectangle, ulong, int); |
| 103 | 105 | Memimage *gscreen; |
| 104 | 106 | Screeninfo screen; |
| @@ -134,6 +136,7 @@ attachscreen(IRectangle *r, ulong *chan, int *depth, · 29 unmodified lines |
| 134 | 136 | void |
| 135 | 137 | flushmemscreen(IRectangle r) |
| 136 | 138 | { |
| 139 | + assert(!drawcanqlock()); |
| 137 | 140 | if(r.min.x >= r.max.x || r.min.y >= r.max.y) |
| 138 | 141 | return; |
| 139 | 142 | 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 |
| 160 | 163 | void |
| 161 | 164 | mouseset(IPoint xy) |
| 162 | 165 | { |
| 166 | + drawqlock(); |
| 163 | 167 | XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, xy.x, xy.y); |
| 164 | 168 | XFlush(xdisplay); |
| 169 | + drawqunlock(); |
| 165 | 170 | } |
| 166 | 171 | |
| 167 | 172 | static Cursor xcursor; |
| @@ -180,6 +185,7 @@ setcursor(void) · 12 unmodified lines |
| 180 | 185 | mask[i] = revbyte(cursor.set[i] | cursor.clr[i]); |
| 181 | 186 | } |
| 182 | 187 | |
| 188 | + drawqlock(); |
| 183 | 189 | fg = map[0]; |
| 184 | 190 | bg = map[255]; |
| 185 | 191 | xsrc = XCreateBitmapFromData(xdisplay, xdrawable, src, 16, 16); |
| @@ -194,17 +200,20 @@ setcursor(void) · 8 unmodified lines |
| 194 | 200 | XFreePixmap(xdisplay, xsrc); |
| 195 | 201 | XFreePixmap(xdisplay, xmask); |
| 196 | 202 | XFlush(xdisplay); |
| 203 | + drawqunlock(); |
| 197 | 204 | } |
| 198 | 205 | |
| 199 | 206 | void |
| 200 | 207 | cursorarrow(void) |
| 201 | 208 | { |
| 209 | + drawqlock(); |
| 202 | 210 | if(xcursor != 0){ |
| 203 | 211 | XFreeCursor(xdisplay, xcursor); |
| 204 | 212 | xcursor = 0; |
| 205 | 213 | } |
| 206 | 214 | XUndefineCursor(xdisplay, xdrawable); |
| 207 | 215 | XFlush(xdisplay); |
| 216 | + drawqunlock(); |
| 208 | 217 | } |
| 209 | 218 | |
| 210 | 219 | static void |
| @@ -229,7 +238,7 @@ xproc(void *arg) · 18 unmodified lines |
| 229 | 238 | for(;;) { |
| 230 | 239 | //XWindowEvent(xkmcon, xdrawable, mask, &event); |
| 231 | 240 | XNextEvent(xkmcon, &event); |
| 232 | | − xselect(&event); |
| 241 | + xselect(&event, xkmcon); |
| 233 | 242 | xkeyboard(&event); |
| 234 | 243 | xmouse(&event); |
| 235 | 244 | xexpose(&event); |
| @@ -464,11 +473,11 @@ xinitscreen(void) · 228 unmodified lines |
| 464 | 473 | exit(0); |
| 465 | 474 | } |
| 466 | 475 | |
| 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); |
| 472 | 481 | |
| 473 | 482 | xblack = screen->black_pixel; |
| 474 | 483 | xwhite = screen->white_pixel; |
| @@ -624,13 +633,6 @@ xdestroy(XEvent *e) · 149 unmodified lines |
| 624 | 633 | exit(0); |
| 625 | 634 | } |
| 626 | 635 | |
| 627 | | −static void |
| 628 | | −xselection(XEvent *e) |
| 629 | | −{ |
| 630 | | − XSelectionRequestEvent *xre; |
| 631 | | − XSelectionEvent *xe; |
| 632 | | −} |
| 633 | | − |
| 634 | 636 | static void |
| 635 | 637 | xmapping(XEvent *e) |
| 636 | 638 | { |
| @@ -691,7 +693,7 @@ xkeyboard(XEvent *e) · 54 unmodified lines |
| 691 | 693 | return; |
| 692 | 694 | |
| 693 | 695 | |
| 694 | | − XLookupString(e,NULL,0,&k,NULL); |
| 696 | + XLookupString((XKeyEvent*)e, NULL, 0, &k, NULL); |
| 695 | 697 | |
| 696 | 698 | if(k == XK_Multi_key || k == NoSymbol) |
| 697 | 699 | return; |
| @@ -781,12 +783,14 @@ xkeyboard(XEvent *e) · 83 unmodified lines |
| 781 | 783 | case XK_Super_R: |
| 782 | 784 | case XK_Hyper_L: |
| 783 | 785 | case XK_Hyper_R: |
| 784 | | − return; |
| 786 | + return; |
| 785 | 787 | 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; |
| 790 | 794 | } |
| 791 | 795 | } |
| 792 | 796 | |
| @@ -811,9 +815,27 @@ xmouse(XEvent *e) · 18 unmodified lines |
| 811 | 815 | XButtonEvent *be; |
| 812 | 816 | XMotionEvent *me; |
| 813 | 817 | |
| 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 | + |
| 814 | 826 | switch(e->type){ |
| 815 | 827 | case ButtonPress: |
| 816 | 828 | 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; |
| 817 | 839 | ms.xy.x = be->x; |
| 818 | 840 | ms.xy.y = be->y; |
| 819 | 841 | s = be->state; |
| @@ -921,174 +943,226 @@ setcolor(ulong i, ulong r, ulong g, ulong b) · 101 unmodified lines |
| 921 | 943 | /* no-op */ |
| 922 | 944 | } |
| 923 | 945 | |
| 924 | | −typedef struct Clip Clip; |
| 925 | | −struct Clip |
| 946 | +int |
| 947 | +atlocalconsole(void) |
| 926 | 948 | { |
| 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]; |
| 935 | 951 | |
| 936 | | −enum { |
| 937 | | − Chunk = 2048 |
| 938 | | −}; |
| 952 | + p = getenv("DRAWTERM_ATLOCALCONSOLE"); |
| 953 | + if(p && atoi(p) == 1) |
| 954 | + return 1; |
| 939 | 955 | |
| 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; |
| 947 | 959 | |
| 960 | + /* extract host part */ |
| 961 | + q = strchr(p, ':'); |
| 962 | + if(q == nil) |
| 963 | + return 0; |
| 964 | + *q = 0; |
| 948 | 965 | |
| 949 | | − if(e->type != SelectionRequest) |
| 950 | | − return; |
| 966 | + if(strcmp(p, "") == 0) |
| 967 | + return 1; |
| 951 | 968 | |
| 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; |
| 978 | 975 | } |
| 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; |
| 988 | 978 | } |
| 989 | 979 | |
| 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 |
| 992 | 986 | { |
| 993 | | − return clip.want == clip.have; |
| 994 | | −} |
| 987 | + char buf[SnarfSize]; |
| 988 | + QLock lk; |
| 989 | +}; |
| 990 | +Clip clip; |
| 995 | 991 | |
| 996 | | −#undef long /* sic */ |
| 997 | | −char* |
| 998 | | −clipread(void) |
| 992 | +#undef long /* sic */ |
| 993 | +#undef ulong |
| 994 | + |
| 995 | +static char* |
| 996 | +_xgetsnarf(Display *xd) |
| 999 | 997 | { |
| 998 | + uchar *data, *xdata; |
| 999 | + Atom clipboard, type, prop; |
| 1000 | + ulong len, lastlen, dummy; |
| 1001 | + int fmt, i; |
| 1000 | 1002 | Window w; |
| 1001 | | − XEvent e; |
| 1002 | | − Atom type; |
| 1003 | | − unsigned long len, lleft, left, dummy; |
| 1004 | | − int i, fmt, res; |
| 1005 | | − uchar *data; |
| 1006 | 1003 | |
| 1007 | 1004 | 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: |
| 1010 | 1018 | 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){ |
| 1012 | 1036 | 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); |
| 1035 | 1078 | }else |
| 1036 | 1079 | data = nil; |
| 1037 | 1080 | } |
| 1081 | +out: |
| 1038 | 1082 | qunlock(&clip.lk); |
| 1039 | 1083 | return (char*)data; |
| 1040 | 1084 | } |
| 1041 | 1085 | |
| 1042 | | −int |
| 1043 | | −clipwrite(char *buf) |
| 1086 | +static void |
| 1087 | +_xputsnarf(Display *xd, char *data) |
| 1044 | 1088 | { |
| 1045 | | − int n; |
| 1089 | + XButtonEvent e; |
| 1046 | 1090 | |
| 1047 | | − n = strlen(buf); |
| 1091 | + if(strlen(data) >= SnarfSize) |
| 1092 | + return; |
| 1048 | 1093 | 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); |
| 1061 | 1107 | qunlock(&clip.lk); |
| 1062 | | − return n; |
| 1063 | 1108 | } |
| 1064 | | −#define long int /* sic */ |
| 1065 | 1109 | |
| 1066 | | −int |
| 1067 | | −atlocalconsole(void) |
| 1110 | +static void |
| 1111 | +xselect(XEvent *e, Display *xd) |
| 1068 | 1112 | { |
| 1069 | | − char *p, *q; |
| 1070 | | − char buf[128]; |
| 1113 | + char *name; |
| 1114 | + XEvent r; |
| 1115 | + XSelectionRequestEvent *xe; |
| 1116 | + Atom a[4]; |
| 1071 | 1117 | |
| 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 | + } |
| 1075 | 1143 | |
| 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 | +} |
| 1081 | 1155 | |
| 1082 | | − if(strcmp(p, "") == 0) |
| 1083 | | − return 1; |
| 1156 | +char* |
| 1157 | +clipread(void) |
| 1158 | +{ |
| 1159 | + return _xgetsnarf(xsnarfcon); |
| 1160 | +} |
| 1084 | 1161 | |
| 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); |
| 1093 | 1166 | return 0; |
| 1094 | 1167 | } |
| 1168 | + |