History

snarf is working (but the code is even uglier than it should)

yiyus committed 15 years ago

Commit 3debbdb1 parent 352b96d7 files · +297 −15Browse files

Unified · Split

7 files
  1. devwsys/dat.h +13 −0
  2. devwsys/fns.h +2 −0
  3. devwsys/ixp_fsys.c +58 −5
  4. devwsys/x11/display.c +4 −0
  5. devwsys/x11/event.c +5 −0
  6. devwsys/x11/itrans.c +212 −10
  7. devwsys/x11/x.h +3 −0
devwsys/dat.h+13−0
@@ -32,6 +32,11 @@ enum { · 31 unmodified lines
3232 CursorSize= 32
3333 };
3434
35+/* snarf buffer size */
36+enum{
37+ SnarfSize= 100*1024
38+};
39+
3540 /* Datatypes: */
3641 typedef struct Client Client;
3742 typedef struct DImage DImage;
@@ -44,6 +49,7 @@ typedef struct Kbdbuf Kbdbuf; · 6 unmodified lines
4449 typedef struct Refresh Refresh;
4550 typedef struct Refx Refx;
4651 typedef struct Cursor Cursor;
52+typedef struct Clip Clip;
4753 typedef struct Window Window;
4854
4955 /* Drawing device */
@@ -167,6 +173,12 @@ struct Cursor { · 117 unmodified lines
167173 uchar mask[(CursorSize/8)*CursorSize];
168174 };
169175
176+/* snarf buffer */
177+struct Clip
178+{
179+ char buf[SnarfSize];
180+};
181+
170182 /* Window system */
171183 struct Window
172184 {
@@ -194,4 +206,5 @@ int nwindow; · 21 unmodified lines
194206 Window **window;
195207 int nclient;
196208 Client **client;
209+Clip clip;
197210
devwsys/fns.h+2−0
@@ -49,3 +49,5 @@ int xupdatelabel(Window*); · 48 unmodified lines
4949 void xtopwindow(Window*);
5050 void xresizewindow(Window*, Rectangle);
5151 void xsetcursor(Window*);
52+char* xgetsnarf(Window*);
53+void xputsnarf(Window*, char*);
devwsys/ixp_fsys.c+58−5
@@ -140,6 +140,8 @@ static IxpDirtab* dirtab[] = { · 139 unmodified lines
140140 typedef char* (*MsgFunc)(void*, IxpMsg*);
141141 typedef char* (*BufFunc)(void*);
142142
143+static char *snarfbuf;
144+
143145 static void
144146 dostat(IxpStat *s, IxpFileId *f) {
145147 s->type = 0;
@@ -367,6 +369,13 @@ fs_open(Ixp9Req *r) { · 221 unmodified lines
367369 w->mouseopen = 1;
368370 ixp_pending_pushfid(w->mousep, r->fid);
369371 break;
372+ case FsFSnarf:
373+ if((r->ifcall.topen.mode&3) == ORDWR){
374+ /* one at a time please */
375+ ixp_respond(r, Enoperm);
376+ return;
377+ }
378+ break;
370379 }
371380
372381 if((r->ifcall.topen.mode&3) == OEXEC
@@ -388,7 +397,7 @@ fs_walk(Ixp9Req *r) { · 15 unmodified lines
388397
389398 void
390399 fs_read(Ixp9Req *r) {
391− char buf[512];
400+ char buf[512], *s;
392401 int n;
393402 IxpFileId *f;
394403 Client *cl;
@@ -461,6 +470,7 @@ fs_read(Ixp9Req *r) { · 66 unmodified lines
461470 }
462471 n = readrefresh(buf, r->ifcall.io.count, cl);
463472 if(n > 0) {
473+
464474 ixp_srv_readbuf(r, buf, n);
465475 ixp_respond(r, nil);
466476 }
@@ -472,6 +482,11 @@ fs_read(Ixp9Req *r) { · 5 unmodified lines
472482 ixp_srv_readbuf(r, w->label, strlen(w->label));
473483 ixp_respond(r, nil);
474484 return;
485+ case FsFSnarf:
486+ s= xgetsnarf(w);
487+ ixp_srv_readbuf(r, s, strlen(s));
488+ ixp_respond(r, nil);
489+ return;
475490 case FsFWctl:
476491 // XXX TODO: visible, current
477492 sprint(buf, "%11d %11d %11d %11d %s %s ", w->orig.x + w->screenr.min.x, w->orig.y + w->screenr.min.y, w->screenr.max.x, w->screenr.max.y, "visible", "current");
@@ -534,7 +549,7 @@ fs_stat(Ixp9Req *r) { · 56 unmodified lines
534549
535550 void
536551 fs_write(Ixp9Req *r) {
537− char *label;
552+ char *label, *p;
538553 char err[256];
539554 IxpFileId *f;
540555 Window *w;
@@ -602,11 +617,38 @@ fs_write(Ixp9Req *r) { · 61 unmodified lines
602617 label[r->ifcall.twrite.count] = 0;
603618 setlabel(w, label);
604619 break;
620+ case FsFSnarf:
621+ if(r->ifcall.twrite.offset+r->ifcall.twrite.count >= SnarfSize){
622+ ixp_respond(r, "too much snarf");
623+ return;
624+ }
625+ if(r->ifcall.twrite.count == 0){
626+ r->ofcall.io.count = r->ifcall.io.count;
627+ break;
628+ }
629+ if(snarfbuf == nil)
630+ r->ofcall.io.count = 0;
631+ else
632+ r->ofcall.io.count = strlen(snarfbuf);
633+ if(r->ifcall.twrite.offset+r->ifcall.twrite.count > r->ofcall.io.count){
634+ r->ofcall.io.count = r->ifcall.twrite.offset+r->ifcall.twrite.count;
635+ p = malloc(r->ofcall.io.count+1);
636+ if(p == nil){
637+ ixp_respond(r, Enomem);
638+ return;
639+ }
640+ if(snarfbuf){
641+ strcpy(p, snarfbuf);
642+ free(snarfbuf);
643+ }
644+ snarfbuf = p;
645+ }
646+ memmove(snarfbuf+r->ifcall.twrite.offset, r->ifcall.twrite.data, r->ifcall.twrite.count);
647+ break;
605648 case FsFWctl:
606649 r->ofcall.io.count = r->ifcall.io.count;
607650 wctlmesg(w, r->ifcall.twrite.data, r->ofcall.rwrite.count, err);
608− ixp_respond(r, nil);
609− return;
651+ break;
610652 }
611653 ixp_respond(r, nil);
612654 }
@@ -639,8 +681,19 @@ fs_clunk(Ixp9Req *r) { · 26 unmodified lines
639681 }
640682
641683 // TODO: ../../inferno-os/emu/port/devdraw.c:971
642− if(f->tab.type == FsFCtl)
684+ switch(f->tab.type){
685+ case FsFCtl:
643686 cl->busy = 0;
687+ case FsFSnarf:
688+ if(r->fid->omode == OWRITE){
689+ if(snarfbuf)
690+ xputsnarf(w, snarfbuf);
691+ else
692+ xputsnarf(w, "");
693+ }
694+ free(snarfbuf);
695+
696+ }
644697 if(!iswindow(f->tab.type) && (decref(&cl->r)==0))
645698 drawfree(cl);
646699 ixp_respond(r, nil);
devwsys/x11/display.c+4−0
@@ -4,6 +4,7 @@ · 3 unmodified lines
44 #include <memlayer.h>
55 #include <cursor.h>
66 #include "dat.h"
7+#include "fns.h"
78 #include "inc.h"
89 #include "x.h"
910
@@ -182,6 +183,9 @@ xinit(void) · 172 unmodified lines
182183 setupcmap(xconn.root);
183184 }
184185 xconn.screenrect = Rect(0, 0, WidthOfScreen(xconn.screen), HeightOfScreen(xconn.screen));
186+
187+ xinitclipboard();
188+
185189 return 0;
186190 }
187191
devwsys/x11/event.c+5−0
@@ -75,6 +75,10 @@ NextEvent: · 74 unmodified lines
7575 writekbd(w, -1);;
7676 break;
7777
78+ case SelectionRequest:
79+ xselect(&xev);
80+ break;
81+
7882 default:
7983 break;
8084 }
@@ -178,6 +182,7 @@ mouseevent(Window *w, XEvent xev) · 97 unmodified lines
178182 {
179183 Mouse m;
180184
185+ xsetsnarfowner(w);
181186 if(xtoplan9mouse(&xev, &m) < 0)
182187 return;
183188 // debugev("Mouse event at window %d: x=%d y=%d b=%d\n", w->id, m.xy.x, m.xy.y, m.buttons);
devwsys/x11/itrans.c+212−10
@@ -8,6 +8,14 @@ · 7 unmodified lines
88 #include "inc.h"
99 #include "x.h"
1010
11+/* for copy/paste, lifted from plan9ports via drawterm */
12+static int putsnarf, assertsnarf;
13+static Atom clipboard;
14+static Atom utf8string;
15+static Atom targets;
16+static Atom text;
17+static Atom compoundtext;
18+
1119 long keysym2ucs(KeySym);
1220 int
1321 xtoplan9kbd(XEvent *e)
@@ -126,16 +134,6 @@ xtoplan9mouse(XEvent *e, Mouse *m) · 112 unmodified lines
126134 XButtonEvent *be;
127135 XMotionEvent *me;
128136
129− /* TODO
130− if(_x.putsnarf != _x.assertsnarf){
131− _x.assertsnarf = _x.putsnarf;
132− XSetSelectionOwner(_x.display, XA_PRIMARY, _x.drawable, CurrentTime);
133− if(_x.clipboard != None)
134− XSetSelectionOwner(_x.display, _x.clipboard, _x.drawable, CurrentTime);
135− XFlush(_x.display);
136− }
137− */
138−
139137 switch(e->type){
140138 case ButtonPress:
141139 be = (XButtonEvent*)e;
@@ -222,3 +220,207 @@ xtoplan9mouse(XEvent *e, Mouse *m) · 80 unmodified lines
222220 m->buttons |= 16;
223221 return 0;
224222 }
223+
224+/*
225+ * Cut and paste. Just couldn't stand to make this simple...
226+ */
227+
228+void
229+xinitclipboard(void){
230+ clipboard = XInternAtom(xconn.display, "CLIPBOARD", False);
231+ utf8string = XInternAtom(xconn.display, "UTF8_STRING", False);
232+ targets = XInternAtom(xconn.display, "TARGETS", False);
233+ text = XInternAtom(xconn.display, "TEXT", False);
234+ compoundtext = XInternAtom(xconn.display, "COMPOUND_TEXT", False);
235+}
236+
237+void
238+xsetsnarfowner(Window *w)
239+{
240+ Xwin *xw;
241+
242+ xw = w->x;
243+ if(putsnarf != assertsnarf){
244+ assertsnarf = putsnarf;
245+ XSetSelectionOwner(xconn.display, XA_PRIMARY, xw->drawable, CurrentTime);
246+ if(clipboard != None)
247+ XSetSelectionOwner(xconn.display, clipboard, xw->drawable, CurrentTime);
248+ XFlush(xconn.display);
249+ }
250+}
251+
252+char*
253+xgetsnarf(Window *window)
254+{
255+ uchar *data, *xdata;
256+ Atom clipboard, type, prop;
257+ unsigned long len, lastlen, dummy;
258+ int fmt, i;
259+ XWindow w, xdrawable;
260+ XDisplay *xd;
261+ Xwin *xw;
262+
263+ /*
264+ * Have we snarfed recently and the X server hasn't caught up?
265+ */
266+ if(putsnarf != assertsnarf)
267+ goto mine;
268+
269+ xd = xconn.display;
270+ xw = window->x;
271+ xdrawable = xw->drawable;
272+
273+ /*
274+ * Is there a primary selection (highlighted text in an xterm)?
275+ */
276+ clipboard = XA_PRIMARY;
277+ w = XGetSelectionOwner(xd, XA_PRIMARY);
278+ if(w == xdrawable){
279+ mine:
280+ data = (uchar*)strdup(clip.buf);
281+ goto out;
282+ }
283+
284+ /*
285+ * If not, is there a clipboard selection?
286+ */
287+ if(w == None && clipboard != None){
288+ clipboard = clipboard;
289+ w = XGetSelectionOwner(xd, clipboard);
290+ if(w == xdrawable)
291+ goto mine;
292+ }
293+
294+ /*
295+ * If not, give up.
296+ */
297+ if(w == None){
298+ data = nil;
299+ goto out;
300+ }
301+
302+ /*
303+ * We should be waiting for SelectionNotify here, but it might never
304+ * come, and we have no way to time out. Instead, we will clear
305+ * local property #1, request our buddy to fill it in for us, and poll
306+ * until he's done or we get tired of waiting.
307+ *
308+ * We should try to go for utf8string instead of XA_STRING,
309+ * but that would add to the polling.
310+ */
311+ prop = 1;
312+ XChangeProperty(xd, xdrawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);
313+ XConvertSelection(xd, clipboard, XA_STRING, prop, xdrawable, CurrentTime);
314+ XFlush(xd);
315+ lastlen = 0;
316+ for(i=0; i<10 || (lastlen!=0 && i<30); i++){
317+ usleep(10*1000);
318+ XGetWindowProperty(xd, xdrawable, prop, 0, 0, 0, AnyPropertyType,
319+ &type, &fmt, &dummy, &len, &data);
320+ if(lastlen == len && len > 0)
321+ break;
322+ lastlen = len;
323+ }
324+ if(i == 10){
325+ data = nil;
326+ goto out;
327+ }
328+ /* get the property */
329+ data = nil;
330+ XGetWindowProperty(xd, xdrawable, prop, 0, SnarfSize/sizeof(unsigned long), 0,
331+ AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
332+ if((type != XA_STRING && type != utf8string) || len == 0){
333+ if(xdata)
334+ XFree(xdata);
335+ data = nil;
336+ }else{
337+ if(xdata){
338+ data = (uchar*)strdup((char*)xdata);
339+ XFree(xdata);
340+ }else
341+ data = nil;
342+ }
343+out:
344+ return (char*)data;
345+}
346+
347+void
348+xputsnarf(Window *window, char *data)
349+{
350+ XButtonEvent e;
351+ XWindow xdrawable;
352+ Xwin *xw;
353+
354+ if(strlen(data) >= SnarfSize)
355+ return;
356+ strcpy(clip.buf, data);
357+
358+ xw = window->x;
359+ xdrawable = xw->drawable;
360+
361+ /* leave note for mouse proc to assert selection ownership */
362+ putsnarf++;
363+
364+ /* send mouse a fake event so snarf is announced */
365+ memset(&e, 0, sizeof e);
366+ e.type = ButtonPress;
367+ e.window = xdrawable;
368+ e.state = ~0;
369+ e.button = ~0;
370+ XSendEvent(xconn.display, xdrawable, True, ButtonPressMask, (XEvent*)&e);
371+ XFlush(xconn.display);
372+}
373+
374+void
375+xselect(XEvent *e)
376+{
377+ char *name;
378+ XEvent r;
379+ XSelectionRequestEvent *xe;
380+ Atom a[4];
381+ XDisplay *xd;
382+
383+ if(e->xany.type != SelectionRequest)
384+ return;
385+
386+ xd = xconn.display;
387+
388+ memset(&r, 0, sizeof r);
389+ xe = (XSelectionRequestEvent*)e;
390+if(0) iprint("xselect target=%d requestor=%d property=%d selection=%d\n",
391+ xe->target, xe->requestor, xe->property, xe->selection);
392+ r.xselection.property = xe->property;
393+ if(xe->target == targets){
394+ a[0] = XA_STRING;
395+ a[1] = utf8string;
396+ a[2] = text;
397+ a[3] = compoundtext;
398+
399+ XChangeProperty(xd, xe->requestor, xe->property, xe->target,
400+ 8, PropModeReplace, (uchar*)a, sizeof a);
401+ }else if(xe->target == XA_STRING || xe->target == utf8string || xe->target == text || xe->target == compoundtext){
402+ /* if the target is STRING we're supposed to reply with Latin1 XXX */
403+ XChangeProperty(xd, xe->requestor, xe->property, xe->target,
404+ 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
405+ }else{
406+ iprint("get %d\n", xe->target);
407+ name = XGetAtomName(xd, xe->target);
408+ if(name == nil)
409+ iprint("XGetAtomName failed\n");
410+ else if(strcmp(name, "TIMESTAMP") != 0)
411+ iprint("%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
412+ r.xselection.property = None;
413+ }
414+
415+ r.xselection.display = xe->display;
416+ /* r.xselection.property filled above */
417+ r.xselection.target = xe->target;
418+ r.xselection.type = SelectionNotify;
419+ r.xselection.requestor = xe->requestor;
420+ r.xselection.time = xe->time;
421+ r.xselection.send_event = True;
422+ r.xselection.selection = xe->selection;
423+ XSendEvent(xd, xe->requestor, False, 0, &r);
424+ XFlush(xd);
425+}
426+
devwsys/x11/x.h+3−0
@@ -70,3 +70,6 @@ void xmovewindow(Window*, Rectangle); · 69 unmodified lines
7070 void xputxdata(Memimage*, Rectangle);
7171 void xmemimagedraw(Memimage*, Rectangle, Memimage*, Point,
7272 Memimage*, Point, int);
73+void xinitclipboard(void);
74+void xsetsnarfowner(Window*);
75+void xselect(XEvent*);