x11-itrans.c (13157B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 #define Image IMAGE /* kernel has its own Image */ 8 #include <draw.h> 9 #include <memdraw.h> 10 #include <keyboard.h> 11 #include <cursor.h> 12 #include "mouse.h" 13 #include "screen.h" 14 #include "x11-inc.h" 15 16 static KeySym 17 _xkeysym(XEvent *e) 18 { 19 KeySym k; 20 21 if(e->xany.type != KeyPress) 22 return -1; 23 // needstack(64*1024); /* X has some *huge* buffers in openobject */ 24 /* and they're even bigger on SuSE */ 25 XLookupString((XKeyEvent*)e,NULL,0,&k,NULL); 26 if(k == XK_Multi_key || k == NoSymbol) 27 return -1; 28 29 if(k&0xFF00){ 30 switch(k){ 31 case XK_BackSpace: 32 case XK_Tab: 33 case XK_Escape: 34 case XK_Delete: 35 case XK_KP_0: 36 case XK_KP_1: 37 case XK_KP_2: 38 case XK_KP_3: 39 case XK_KP_4: 40 case XK_KP_5: 41 case XK_KP_6: 42 case XK_KP_7: 43 case XK_KP_8: 44 case XK_KP_9: 45 case XK_KP_Divide: 46 case XK_KP_Multiply: 47 case XK_KP_Subtract: 48 case XK_KP_Add: 49 case XK_KP_Decimal: 50 k &= 0x7F; 51 break; 52 case XK_Linefeed: 53 k = '\r'; 54 break; 55 case XK_KP_Space: 56 k = ' '; 57 break; 58 case XK_Home: 59 case XK_KP_Home: 60 k = Khome; 61 break; 62 case XK_Left: 63 case XK_KP_Left: 64 k = Kleft; 65 break; 66 case XK_Up: 67 case XK_KP_Up: 68 k = Kup; 69 break; 70 case XK_Down: 71 case XK_KP_Down: 72 k = Kdown; 73 break; 74 case XK_Right: 75 case XK_KP_Right: 76 k = Kright; 77 break; 78 case XK_Page_Down: 79 case XK_KP_Page_Down: 80 k = Kpgdown; 81 break; 82 case XK_End: 83 case XK_KP_End: 84 k = Kend; 85 break; 86 case XK_Page_Up: 87 case XK_KP_Page_Up: 88 k = Kpgup; 89 break; 90 case XK_Insert: 91 case XK_KP_Insert: 92 k = Kins; 93 break; 94 case XK_KP_Enter: 95 case XK_Return: 96 k = '\n'; 97 break; 98 case XK_Alt_L: 99 case XK_Meta_L: /* Shift Alt on PCs */ 100 case XK_Alt_R: 101 case XK_Meta_R: /* Shift Alt on PCs */ 102 k = Kalt; 103 break; 104 default: /* not ISO-1 or tty control */ 105 if(k>0xff) 106 return _xkeysym2rune(k); 107 break; 108 } 109 } 110 111 /* Compensate for servers that call a minus a hyphen */ 112 if(k == XK_hyphen) 113 k = XK_minus; 114 /* Do control mapping ourselves if translator doesn't */ 115 if(e->xkey.state&ControlMask && k != Kalt) 116 k &= 0x9f; 117 if(k == NoSymbol) 118 return -1; 119 return k; 120 } 121 122 static void 123 xputc(int c) 124 { 125 kbdputc(kbdq, c); 126 } 127 128 void 129 _xtoplan9kbd(XEvent *e) 130 { 131 int r; 132 133 r = _xkeysym(e); 134 if(r > 0) 135 latin1putc(r, xputc); 136 } 137 138 int 139 _xtoplan9mouse(XEvent *e, Mouse *m) 140 { 141 int s; 142 XButtonEvent *be; 143 XMotionEvent *me; 144 145 if(_x.putsnarf != _x.assertsnarf){ 146 _x.assertsnarf = _x.putsnarf; 147 XSetSelectionOwner(_x.kmcon, XA_PRIMARY, _x.drawable, CurrentTime); 148 if(_x.clipboard != None) 149 XSetSelectionOwner(_x.kmcon, _x.clipboard, _x.drawable, CurrentTime); 150 XFlush(_x.kmcon); 151 } 152 153 switch(e->type){ 154 case ButtonPress: 155 be = (XButtonEvent*)e; 156 /* 157 * Fake message, just sent to make us announce snarf. 158 * Apparently state and button are 16 and 8 bits on 159 * the wire, since they are truncated by the time they 160 * get to us. 161 */ 162 if(be->send_event 163 && (~be->state&0xFFFF)==0 164 && (~be->button&0xFF)==0) 165 return -1; 166 /* BUG? on mac need to inherit these from elsewhere? */ 167 m->xy.x = be->x; 168 m->xy.y = be->y; 169 s = be->state; 170 m->msec = be->time; 171 switch(be->button){ 172 case 1: 173 s |= Button1Mask; 174 break; 175 case 2: 176 s |= Button2Mask; 177 break; 178 case 3: 179 s |= Button3Mask; 180 break; 181 case 4: 182 s |= Button4Mask; 183 break; 184 case 5: 185 s |= Button5Mask; 186 break; 187 } 188 break; 189 case ButtonRelease: 190 be = (XButtonEvent*)e; 191 m->xy.x = be->x; 192 m->xy.y = be->y; 193 s = be->state; 194 m->msec = be->time; 195 switch(be->button){ 196 case 1: 197 s &= ~Button1Mask; 198 break; 199 case 2: 200 s &= ~Button2Mask; 201 break; 202 case 3: 203 s &= ~Button3Mask; 204 break; 205 case 4: 206 s &= ~Button4Mask; 207 break; 208 case 5: 209 s &= ~Button5Mask; 210 break; 211 } 212 break; 213 214 case MotionNotify: 215 me = (XMotionEvent*)e; 216 s = me->state; 217 m->xy.x = me->x; 218 m->xy.y = me->y; 219 m->msec = me->time; 220 break; 221 222 default: 223 return -1; 224 } 225 226 m->buttons = 0; 227 if(s & Button1Mask) 228 m->buttons |= 1; 229 if(s & Button2Mask) 230 m->buttons |= 2; 231 if(s & Button3Mask) 232 m->buttons |= s & ShiftMask ? 2 : 4; 233 if(s & Button4Mask) 234 m->buttons |= 8; 235 if(s & Button5Mask) 236 m->buttons |= 16; 237 return 0; 238 } 239 240 void 241 _xmoveto(Point p) 242 { 243 XWarpPointer(_x.display, None, _x.drawable, 0, 0, 0, 0, p.x, p.y); 244 XFlush(_x.display); 245 } 246 247 static int 248 revbyte(int b) 249 { 250 int r; 251 252 r = 0; 253 r |= (b&0x01) << 7; 254 r |= (b&0x02) << 5; 255 r |= (b&0x04) << 3; 256 r |= (b&0x08) << 1; 257 r |= (b&0x10) >> 1; 258 r |= (b&0x20) >> 3; 259 r |= (b&0x40) >> 5; 260 r |= (b&0x80) >> 7; 261 return r; 262 } 263 264 static void 265 xcursorarrow(void) 266 { 267 if(_x.cursor != 0){ 268 XFreeCursor(_x.display, _x.cursor); 269 _x.cursor = 0; 270 } 271 XUndefineCursor(_x.display, _x.drawable); 272 XFlush(_x.display); 273 } 274 275 void 276 _xsetcursor(Cursor *c) 277 { 278 XColor fg, bg; 279 XCursor xc; 280 Pixmap xsrc, xmask; 281 int i; 282 uchar src[2*16], mask[2*16]; 283 284 if(_x.display == nil) 285 return; 286 287 if(c == nil){ 288 xcursorarrow(); 289 return; 290 } 291 for(i=0; i<2*16; i++){ 292 src[i] = revbyte(c->set[i]); 293 mask[i] = revbyte(c->set[i] | c->clr[i]); 294 } 295 296 fg = _x.map[0]; 297 bg = _x.map[255]; 298 xsrc = XCreateBitmapFromData(_x.display, _x.drawable, (char*)src, 16, 16); 299 xmask = XCreateBitmapFromData(_x.display, _x.drawable, (char*)mask, 16, 16); 300 xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y); 301 if(xc != 0) { 302 XDefineCursor(_x.display, _x.drawable, xc); 303 if(_x.cursor != 0) 304 XFreeCursor(_x.display, _x.cursor); 305 _x.cursor = xc; 306 } 307 XFreePixmap(_x.display, xsrc); 308 XFreePixmap(_x.display, xmask); 309 XFlush(_x.display); 310 } 311 312 void 313 setcursor(Cursor *c) 314 { 315 drawqlock(); 316 _xsetcursor(c); 317 drawqunlock(); 318 } 319 320 struct { 321 QLock lk; 322 char buf[SnarfSize]; 323 #ifdef APPLESNARF 324 Rune rbuf[SnarfSize]; 325 PasteboardRef apple; 326 #endif 327 } clip; 328 329 static uchar* 330 _xgetsnarffrom(XWindow w, Atom clipboard, Atom target, int timeout0, int timeout) 331 { 332 Atom prop, type; 333 ulong len, lastlen, dummy; 334 int fmt, i; 335 uchar *data, *xdata; 336 337 /* 338 * We should be waiting for SelectionNotify here, but it might never 339 * come, and we have no way to time out. Instead, we will clear 340 * local property #1, request our buddy to fill it in for us, and poll 341 * until he's done or we get tired of waiting. 342 */ 343 prop = 1; 344 XChangeProperty(_x.display, _x.drawable, prop, target, 8, PropModeReplace, (uchar*)"", 0); 345 XConvertSelection(_x.display, clipboard, target, prop, _x.drawable, CurrentTime); 346 XFlush(_x.display); 347 lastlen = 0; 348 timeout0 = (timeout0 + 9)/10; 349 timeout = (timeout + 9)/10; 350 for(i=0; i<timeout0 || (lastlen!=0 && i<timeout); i++){ 351 usleep(10*1000); 352 XGetWindowProperty(_x.display, _x.drawable, prop, 0, 0, 0, AnyPropertyType, 353 &type, &fmt, &dummy, &len, &xdata); 354 if(lastlen == len && len > 0) 355 break; 356 lastlen = len; 357 XFree(xdata); 358 } 359 if(len == 0) 360 return nil; 361 362 /* get the property */ 363 xdata = nil; 364 XGetWindowProperty(_x.display, _x.drawable, prop, 0, SnarfSize/sizeof(uint32), 0, 365 AnyPropertyType, &type, &fmt, &len, &dummy, &xdata); 366 if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){ 367 if(xdata) 368 XFree(xdata); 369 return nil; 370 } 371 if(xdata){ 372 data = (uchar*)strdup((char*)xdata); 373 XFree(xdata); 374 return data; 375 } 376 return nil; 377 } 378 379 char* 380 _xgetsnarf(void) 381 { 382 uchar *data; 383 Atom clipboard; 384 XWindow w; 385 386 qlock(&clip.lk); 387 /* 388 * Have we snarfed recently and the X server hasn't caught up? 389 */ 390 if(_x.putsnarf != _x.assertsnarf) 391 goto mine; 392 393 /* 394 * Is there a primary selection (highlighted text in an xterm)? 395 */ 396 clipboard = XA_PRIMARY; 397 w = XGetSelectionOwner(_x.display, XA_PRIMARY); 398 if(w == _x.drawable){ 399 mine: 400 data = (uchar*)strdup(clip.buf); 401 goto out; 402 } 403 404 /* 405 * If not, is there a clipboard selection? 406 */ 407 if(w == None && _x.clipboard != None){ 408 clipboard = _x.clipboard; 409 w = XGetSelectionOwner(_x.display, _x.clipboard); 410 if(w == _x.drawable) 411 goto mine; 412 } 413 414 /* 415 * If not, give up. 416 */ 417 if(w == None){ 418 data = nil; 419 goto out; 420 } 421 422 if((data = _xgetsnarffrom(w, clipboard, _x.utf8string, 10, 100)) == nil) 423 if((data = _xgetsnarffrom(w, clipboard, XA_STRING, 10, 100)) == nil){ 424 /* nothing left to do */ 425 } 426 427 out: 428 qunlock(&clip.lk); 429 return (char*)data; 430 } 431 432 void 433 __xputsnarf(char *data) 434 { 435 XButtonEvent e; 436 437 if(strlen(data) >= SnarfSize) 438 return; 439 qlock(&clip.lk); 440 strcpy(clip.buf, data); 441 /* leave note for mouse proc to assert selection ownership */ 442 _x.putsnarf++; 443 444 /* send mouse a fake event so snarf is announced */ 445 memset(&e, 0, sizeof e); 446 e.type = ButtonPress; 447 e.window = _x.drawable; 448 e.state = ~0; 449 e.button = ~0; 450 XSendEvent(_x.snarfcon, _x.drawable, True, ButtonPressMask, (XEvent*)&e); 451 XFlush(_x.snarfcon); 452 qunlock(&clip.lk); 453 } 454 455 int 456 _xselect(XEvent *e) 457 { 458 char *name; 459 XEvent r; 460 XSelectionRequestEvent *xe; 461 Atom a[4]; 462 463 memset(&r, 0, sizeof r); 464 xe = (XSelectionRequestEvent*)e; 465 if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n", 466 xe->target, xe->requestor, xe->property, xe->selection); 467 r.xselection.property = xe->property; 468 if(xe->target == _x.targets){ 469 a[0] = _x.utf8string; 470 a[1] = XA_STRING; 471 a[2] = _x.text; 472 a[3] = _x.compoundtext; 473 474 XChangeProperty(_x.kmcon, xe->requestor, xe->property, xe->target, 475 8*sizeof(a[0]), PropModeReplace, (uchar*)a, nelem(a)); 476 }else if(xe->target == XA_STRING 477 || xe->target == _x.utf8string 478 || xe->target == _x.text 479 || xe->target == _x.compoundtext 480 || ((name = XGetAtomName(_x.kmcon, xe->target)) && strcmp(name, "text/plain;charset=UTF-8") == 0)){ 481 /* text/plain;charset=UTF-8 seems nonstandard but is used by Synergy */ 482 /* if the target is STRING we're supposed to reply with Latin1 XXX */ 483 qlock(&clip.lk); 484 XChangeProperty(_x.kmcon, xe->requestor, xe->property, xe->target, 485 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf)); 486 qunlock(&clip.lk); 487 }else{ 488 if(strcmp(name, "TIMESTAMP") != 0) 489 fprint(2, "9vx: cannot handle selection request for '%s' (%d)\n", name, (int)xe->target); 490 r.xselection.property = None; 491 } 492 493 r.xselection.display = xe->display; 494 /* r.xselection.property filled above */ 495 r.xselection.target = xe->target; 496 r.xselection.type = SelectionNotify; 497 r.xselection.requestor = xe->requestor; 498 r.xselection.time = xe->time; 499 r.xselection.send_event = True; 500 r.xselection.selection = xe->selection; 501 XSendEvent(_x.kmcon, xe->requestor, False, 0, &r); 502 XFlush(_x.kmcon); 503 return 0; 504 } 505 506 #ifdef APPLESNARF 507 char* 508 _applegetsnarf(void) 509 { 510 char *s, *t; 511 CFArrayRef flavors; 512 CFDataRef data; 513 CFIndex nflavor, ndata, j; 514 CFStringRef type; 515 ItemCount nitem; 516 PasteboardItemID id; 517 PasteboardSyncFlags flags; 518 UInt32 i; 519 520 /* fprint(2, "applegetsnarf\n"); */ 521 qlock(&clip.lk); 522 if(clip.apple == nil){ 523 if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){ 524 fprint(2, "apple pasteboard create failed\n"); 525 qunlock(&clip.lk); 526 return nil; 527 } 528 } 529 flags = PasteboardSynchronize(clip.apple); 530 if(flags&kPasteboardClientIsOwner){ 531 s = strdup(clip.buf); 532 qunlock(&clip.lk); 533 return s; 534 } 535 if(PasteboardGetItemCount(clip.apple, &nitem) != noErr){ 536 fprint(2, "apple pasteboard get item count failed\n"); 537 qunlock(&clip.lk); 538 return nil; 539 } 540 for(i=1; i<=nitem; i++){ 541 if(PasteboardGetItemIdentifier(clip.apple, i, &id) != noErr) 542 continue; 543 if(PasteboardCopyItemFlavors(clip.apple, id, &flavors) != noErr) 544 continue; 545 nflavor = CFArrayGetCount(flavors); 546 for(j=0; j<nflavor; j++){ 547 type = (CFStringRef)CFArrayGetValueAtIndex(flavors, j); 548 if(!UTTypeConformsTo(type, CFSTR("public.utf16-plain-text"))) 549 continue; 550 if(PasteboardCopyItemFlavorData(clip.apple, id, type, &data) != noErr) 551 continue; 552 ndata = CFDataGetLength(data); 553 qunlock(&clip.lk); 554 s = smprint("%.*S", ndata/2, (Rune*)CFDataGetBytePtr(data)); 555 CFRelease(flavors); 556 CFRelease(data); 557 for(t=s; *t; t++) 558 if(*t == '\r') 559 *t = '\n'; 560 return s; 561 } 562 CFRelease(flavors); 563 } 564 qunlock(&clip.lk); 565 return nil; 566 } 567 568 void 569 _appleputsnarf(char *s) 570 { 571 CFDataRef cfdata; 572 PasteboardSyncFlags flags; 573 574 /* fprint(2, "appleputsnarf\n"); */ 575 576 if(strlen(s) >= SnarfSize) 577 return; 578 qlock(&clip.lk); 579 strcpy(clip.buf, s); 580 runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s); 581 if(clip.apple == nil){ 582 if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){ 583 fprint(2, "apple pasteboard create failed\n"); 584 qunlock(&clip.lk); 585 return; 586 } 587 } 588 if(PasteboardClear(clip.apple) != noErr){ 589 fprint(2, "apple pasteboard clear failed\n"); 590 qunlock(&clip.lk); 591 return; 592 } 593 flags = PasteboardSynchronize(clip.apple); 594 if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){ 595 fprint(2, "apple pasteboard cannot assert ownership\n"); 596 qunlock(&clip.lk); 597 return; 598 } 599 cfdata = CFDataCreate(kCFAllocatorDefault, 600 (uchar*)clip.rbuf, runestrlen(clip.rbuf)*2); 601 if(cfdata == nil){ 602 fprint(2, "apple pasteboard cfdatacreate failed\n"); 603 qunlock(&clip.lk); 604 return; 605 } 606 if(PasteboardPutItemFlavor(clip.apple, (PasteboardItemID)1, 607 CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){ 608 fprint(2, "apple pasteboard putitem failed\n"); 609 CFRelease(cfdata); 610 qunlock(&clip.lk); 611 return; 612 } 613 /* CFRelease(cfdata); ??? */ 614 qunlock(&clip.lk); 615 } 616 #endif /* APPLESNARF */ 617 618 void 619 _xputsnarf(char *data) 620 { 621 #ifdef APPLESNARF 622 _appleputsnarf(data); 623 #endif 624 __xputsnarf(data); 625 }