vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

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 }