Unified · Split
| @@ -32,6 +32,11 @@ enum { · 31 unmodified lines | ||
| 32 | 32 | CursorSize= 32 |
| 33 | 33 | }; |
| 34 | 34 | |
| 35 | +/* snarf buffer size */ | |
| 36 | +enum{ | |
| 37 | + SnarfSize= 100*1024 | |
| 38 | +}; | |
| 39 | + | |
| 35 | 40 | /* Datatypes: */ |
| 36 | 41 | typedef struct Client Client; |
| 37 | 42 | typedef struct DImage DImage; |
| @@ -44,6 +49,7 @@ typedef struct Kbdbuf Kbdbuf; · 6 unmodified lines | ||
| 44 | 49 | typedef struct Refresh Refresh; |
| 45 | 50 | typedef struct Refx Refx; |
| 46 | 51 | typedef struct Cursor Cursor; |
| 52 | +typedef struct Clip Clip; | |
| 47 | 53 | typedef struct Window Window; |
| 48 | 54 | |
| 49 | 55 | /* Drawing device */ |
| @@ -167,6 +173,12 @@ struct Cursor { · 117 unmodified lines | ||
| 167 | 173 | uchar mask[(CursorSize/8)*CursorSize]; |
| 168 | 174 | }; |
| 169 | 175 | |
| 176 | +/* snarf buffer */ | |
| 177 | +struct Clip | |
| 178 | +{ | |
| 179 | + char buf[SnarfSize]; | |
| 180 | +}; | |
| 181 | + | |
| 170 | 182 | /* Window system */ |
| 171 | 183 | struct Window |
| 172 | 184 | { |
| @@ -194,4 +206,5 @@ int nwindow; · 21 unmodified lines | ||
| 194 | 206 | Window **window; |
| 195 | 207 | int nclient; |
| 196 | 208 | Client **client; |
| 209 | +Clip clip; | |
| 197 | 210 | |
| @@ -49,3 +49,5 @@ int xupdatelabel(Window*); · 48 unmodified lines | ||
| 49 | 49 | void xtopwindow(Window*); |
| 50 | 50 | void xresizewindow(Window*, Rectangle); |
| 51 | 51 | void xsetcursor(Window*); |
| 52 | +char* xgetsnarf(Window*); | |
| 53 | +void xputsnarf(Window*, char*); | |
| @@ -140,6 +140,8 @@ static IxpDirtab* dirtab[] = { · 139 unmodified lines | ||
| 140 | 140 | typedef char* (*MsgFunc)(void*, IxpMsg*); |
| 141 | 141 | typedef char* (*BufFunc)(void*); |
| 142 | 142 | |
| 143 | +static char *snarfbuf; | |
| 144 | + | |
| 143 | 145 | static void |
| 144 | 146 | dostat(IxpStat *s, IxpFileId *f) { |
| 145 | 147 | s->type = 0; |
| @@ -367,6 +369,13 @@ fs_open(Ixp9Req *r) { · 221 unmodified lines | ||
| 367 | 369 | w->mouseopen = 1; |
| 368 | 370 | ixp_pending_pushfid(w->mousep, r->fid); |
| 369 | 371 | 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; | |
| 370 | 379 | } |
| 371 | 380 | |
| 372 | 381 | if((r->ifcall.topen.mode&3) == OEXEC |
| @@ -388,7 +397,7 @@ fs_walk(Ixp9Req *r) { · 15 unmodified lines | ||
| 388 | 397 | |
| 389 | 398 | void |
| 390 | 399 | fs_read(Ixp9Req *r) { |
| 391 | − char buf[512]; | |
| 400 | + char buf[512], *s; | |
| 392 | 401 | int n; |
| 393 | 402 | IxpFileId *f; |
| 394 | 403 | Client *cl; |
| @@ -461,6 +470,7 @@ fs_read(Ixp9Req *r) { · 66 unmodified lines | ||
| 461 | 470 | } |
| 462 | 471 | n = readrefresh(buf, r->ifcall.io.count, cl); |
| 463 | 472 | if(n > 0) { |
| 473 | + | |
| 464 | 474 | ixp_srv_readbuf(r, buf, n); |
| 465 | 475 | ixp_respond(r, nil); |
| 466 | 476 | } |
| @@ -472,6 +482,11 @@ fs_read(Ixp9Req *r) { · 5 unmodified lines | ||
| 472 | 482 | ixp_srv_readbuf(r, w->label, strlen(w->label)); |
| 473 | 483 | ixp_respond(r, nil); |
| 474 | 484 | return; |
| 485 | + case FsFSnarf: | |
| 486 | + s= xgetsnarf(w); | |
| 487 | + ixp_srv_readbuf(r, s, strlen(s)); | |
| 488 | + ixp_respond(r, nil); | |
| 489 | + return; | |
| 475 | 490 | case FsFWctl: |
| 476 | 491 | // XXX TODO: visible, current |
| 477 | 492 | 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 | ||
| 534 | 549 | |
| 535 | 550 | void |
| 536 | 551 | fs_write(Ixp9Req *r) { |
| 537 | − char *label; | |
| 552 | + char *label, *p; | |
| 538 | 553 | char err[256]; |
| 539 | 554 | IxpFileId *f; |
| 540 | 555 | Window *w; |
| @@ -602,11 +617,38 @@ fs_write(Ixp9Req *r) { · 61 unmodified lines | ||
| 602 | 617 | label[r->ifcall.twrite.count] = 0; |
| 603 | 618 | setlabel(w, label); |
| 604 | 619 | 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; | |
| 605 | 648 | case FsFWctl: |
| 606 | 649 | r->ofcall.io.count = r->ifcall.io.count; |
| 607 | 650 | wctlmesg(w, r->ifcall.twrite.data, r->ofcall.rwrite.count, err); |
| 608 | − ixp_respond(r, nil); | |
| 609 | − return; | |
| 651 | + break; | |
| 610 | 652 | } |
| 611 | 653 | ixp_respond(r, nil); |
| 612 | 654 | } |
| @@ -639,8 +681,19 @@ fs_clunk(Ixp9Req *r) { · 26 unmodified lines | ||
| 639 | 681 | } |
| 640 | 682 | |
| 641 | 683 | // TODO: ../../inferno-os/emu/port/devdraw.c:971 |
| 642 | − if(f->tab.type == FsFCtl) | |
| 684 | + switch(f->tab.type){ | |
| 685 | + case FsFCtl: | |
| 643 | 686 | 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 | + } | |
| 644 | 697 | if(!iswindow(f->tab.type) && (decref(&cl->r)==0)) |
| 645 | 698 | drawfree(cl); |
| 646 | 699 | ixp_respond(r, nil); |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | ||
| 4 | 4 | #include <memlayer.h> |
| 5 | 5 | #include <cursor.h> |
| 6 | 6 | #include "dat.h" |
| 7 | +#include "fns.h" | |
| 7 | 8 | #include "inc.h" |
| 8 | 9 | #include "x.h" |
| 9 | 10 | |
| @@ -182,6 +183,9 @@ xinit(void) · 172 unmodified lines | ||
| 182 | 183 | setupcmap(xconn.root); |
| 183 | 184 | } |
| 184 | 185 | xconn.screenrect = Rect(0, 0, WidthOfScreen(xconn.screen), HeightOfScreen(xconn.screen)); |
| 186 | + | |
| 187 | + xinitclipboard(); | |
| 188 | + | |
| 185 | 189 | return 0; |
| 186 | 190 | } |
| 187 | 191 | |
| @@ -75,6 +75,10 @@ NextEvent: · 74 unmodified lines | ||
| 75 | 75 | writekbd(w, -1);; |
| 76 | 76 | break; |
| 77 | 77 | |
| 78 | + case SelectionRequest: | |
| 79 | + xselect(&xev); | |
| 80 | + break; | |
| 81 | + | |
| 78 | 82 | default: |
| 79 | 83 | break; |
| 80 | 84 | } |
| @@ -178,6 +182,7 @@ mouseevent(Window *w, XEvent xev) · 97 unmodified lines | ||
| 178 | 182 | { |
| 179 | 183 | Mouse m; |
| 180 | 184 | |
| 185 | + xsetsnarfowner(w); | |
| 181 | 186 | if(xtoplan9mouse(&xev, &m) < 0) |
| 182 | 187 | return; |
| 183 | 188 | // debugev("Mouse event at window %d: x=%d y=%d b=%d\n", w->id, m.xy.x, m.xy.y, m.buttons); |
| @@ -8,6 +8,14 @@ · 7 unmodified lines | ||
| 8 | 8 | #include "inc.h" |
| 9 | 9 | #include "x.h" |
| 10 | 10 | |
| 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 | + | |
| 11 | 19 | long keysym2ucs(KeySym); |
| 12 | 20 | int |
| 13 | 21 | xtoplan9kbd(XEvent *e) |
| @@ -126,16 +134,6 @@ xtoplan9mouse(XEvent *e, Mouse *m) · 112 unmodified lines | ||
| 126 | 134 | XButtonEvent *be; |
| 127 | 135 | XMotionEvent *me; |
| 128 | 136 | |
| 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 | − | |
| 139 | 137 | switch(e->type){ |
| 140 | 138 | case ButtonPress: |
| 141 | 139 | be = (XButtonEvent*)e; |
| @@ -222,3 +220,207 @@ xtoplan9mouse(XEvent *e, Mouse *m) · 80 unmodified lines | ||
| 222 | 220 | m->buttons |= 16; |
| 223 | 221 | return 0; |
| 224 | 222 | } |
| 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 | + | |
| @@ -70,3 +70,6 @@ void xmovewindow(Window*, Rectangle); · 69 unmodified lines | ||
| 70 | 70 | void xputxdata(Memimage*, Rectangle); |
| 71 | 71 | void xmemimagedraw(Memimage*, Rectangle, Memimage*, Point, |
| 72 | 72 | Memimage*, Point, int); |
| 73 | +void xinitclipboard(void); | |
| 74 | +void xsetsnarfowner(Window*); | |
| 75 | +void xselect(XEvent*); | |