Blob
- Date:
- Message:
- Fighting the good fight. Move libfmt, libutf into subdirectories of lib9. Add poll-based socket i/o to libthread, so that we can avoid using multiple procs when possible, thus removing dependence on crappy pthreads implementations. Convert samterm, acme to the single-proc libthread. Bring libcomplete, acme up-to-date w.r.t. Plan 9 distribution.
- Actions:
- History | Blame | Raw File
1 /* input event and data structure translation */3 #include "x11-inc.h"5 #include <u.h>6 #include <libc.h>7 #include <draw.h>8 #include <memdraw.h>9 #include <mouse.h>10 #include <cursor.h>11 #include <keyboard.h>12 #include "x11-memdraw.h"14 static int15 __xtoplan9kbd(XEvent *e)16 {17 int ind, k, md;19 md = e->xkey.state;20 ind = 0;21 if(md & ShiftMask)22 ind = 1;24 k = XKeycodeToKeysym(e->xany.display, (KeyCode)e->xkey.keycode, ind);25 if(k == XK_Multi_key || k == NoSymbol)26 return -1;28 if(k&0xFF00){29 switch(k){30 case XK_BackSpace:31 case XK_Tab:32 case XK_Escape:33 case XK_Delete:34 case XK_KP_0:35 case XK_KP_1:36 case XK_KP_2:37 case XK_KP_3:38 case XK_KP_4:39 case XK_KP_5:40 case XK_KP_6:41 case XK_KP_7:42 case XK_KP_8:43 case XK_KP_9:44 case XK_KP_Divide:45 case XK_KP_Multiply:46 case XK_KP_Subtract:47 case XK_KP_Add:48 case XK_KP_Decimal:49 k &= 0x7F;50 break;51 case XK_Linefeed:52 k = '\r';53 break;54 case XK_KP_Space:55 k = ' ';56 break;57 case XK_Home:58 case XK_KP_Home:59 k = Khome;60 break;61 case XK_Left:62 case XK_KP_Left:63 k = Kleft;64 break;65 case XK_Up:66 case XK_KP_Up:67 k = Kup;68 break;69 case XK_Down:70 case XK_KP_Down:71 k = Kdown;72 break;73 case XK_Right:74 case XK_KP_Right:75 k = Kright;76 break;77 case XK_Page_Down:78 case XK_KP_Page_Down:79 k = Kpgdown;80 break;81 case XK_End:82 case XK_KP_End:83 k = Kend;84 break;85 case XK_Page_Up:86 case XK_KP_Page_Up:87 k = Kpgup;88 break;89 case XK_Insert:90 case XK_KP_Insert:91 k = Kins;92 break;93 case XK_KP_Enter:94 case XK_Return:95 k = '\n';96 break;97 case XK_Alt_L:98 case XK_Alt_R:99 k = Kalt;100 break;101 default: /* not ISO-1 or tty control */102 return -1;103 }104 }106 /* Compensate for servers that call a minus a hyphen */107 if(k == XK_hyphen)108 k = XK_minus;109 /* Do control mapping ourselves if translator doesn't */110 if(e->xkey.state&ControlMask)111 k &= 0x9f;112 if(k == NoSymbol) {113 return -1;114 }116 /* BUG: could/should do Alt translation here! */117 return k;118 }120 static Rune*121 xtoplan9latin1(XEvent *e)122 {123 static Rune k[10];124 static int alting, nk;125 int n;126 int r;128 r = __xtoplan9kbd(e);129 if(r < 0)130 return nil;131 if(alting){132 k[nk++] = r;133 n = _latin1(k, nk);134 if(n > 0){135 alting = 0;136 k[0] = n;137 k[1] = 0;138 return k;139 }140 if(n == -1){141 alting = 0;142 k[nk] = 0;143 return k;144 }145 /* n < -1, need more input */146 return nil;147 }else if(r == Kalt){148 alting = 1;149 nk = 0;150 return nil;151 }else{152 k[0] = r;153 k[1] = 0;154 return k;155 }156 }158 int159 _xtoplan9kbd(XEvent *e)160 {161 static Rune *r;163 if(e == (XEvent*)-1){164 assert(r);165 r--;166 return 0;167 }168 if(e)169 r = xtoplan9latin1(e);170 if(r && *r)171 return *r++;172 return -1;173 }175 int176 _xtoplan9mouse(XDisplay *xd, XEvent *e, Mouse *m)177 {178 int s;179 XButtonEvent *be;180 XMotionEvent *me;182 if(_x.putsnarf != _x.assertsnarf){183 _x.assertsnarf = _x.putsnarf;184 XSetSelectionOwner(_x.mousecon, XA_PRIMARY, _x.drawable, CurrentTime);185 if(_x.clipboard != None)186 XSetSelectionOwner(_x.mousecon, _x.clipboard, _x.drawable, CurrentTime);187 XFlush(xd);188 }190 switch(e->type){191 case ButtonPress:192 be = (XButtonEvent*)e;193 /*194 * Fake message, just sent to make us announce snarf.195 * Apparently state and button are 16 and 8 bits on196 * the wire, since they are truncated by the time they197 * get to us.198 */199 if(be->send_event200 && (~be->state&0xFFFF)==0201 && (~be->button&0xFF)==0)202 return -1;203 /* BUG? on mac need to inherit these from elsewhere? */204 m->xy.x = be->x;205 m->xy.y = be->y;206 s = be->state;207 m->msec = be->time;208 switch(be->button){209 case 1:210 s |= Button1Mask;211 break;212 case 2:213 s |= Button2Mask;214 break;215 case 3:216 s |= Button3Mask;217 break;218 }219 break;220 case ButtonRelease:221 be = (XButtonEvent*)e;222 m->xy.x = be->x;223 m->xy.y = be->y;224 s = be->state;225 m->msec = be->time;226 switch(be->button){227 case 1:228 s &= ~Button1Mask;229 break;230 case 2:231 s &= ~Button2Mask;232 break;233 case 3:234 s &= ~Button3Mask;235 break;236 }237 break;239 case MotionNotify:240 me = (XMotionEvent*)e;241 s = me->state;242 m->xy.x = me->x;243 m->xy.y = me->y;244 m->msec = me->time;245 break;247 default:248 return -1;249 }251 m->buttons = 0;252 if(s & Button1Mask)253 m->buttons |= 1;254 if(s & Button2Mask)255 m->buttons |= 2;256 if(s & Button3Mask)257 m->buttons |= 4;259 return 0;260 }262 void263 _xmoveto(Point p)264 {265 XWarpPointer(_x.display, None, _x.drawable, 0, 0, 0, 0, p.x, p.y);266 XFlush(_x.display);267 }269 static int270 revbyte(int b)271 {272 int r;274 r = 0;275 r |= (b&0x01) << 7;276 r |= (b&0x02) << 5;277 r |= (b&0x04) << 3;278 r |= (b&0x08) << 1;279 r |= (b&0x10) >> 1;280 r |= (b&0x20) >> 3;281 r |= (b&0x40) >> 5;282 r |= (b&0x80) >> 7;283 return r;284 }286 static void287 xcursorarrow(void)288 {289 if(_x.cursor != 0){290 XFreeCursor(_x.display, _x.cursor);291 _x.cursor = 0;292 }293 XUndefineCursor(_x.display, _x.drawable);294 XFlush(_x.display);295 }298 void299 _xsetcursor(Cursor *c)300 {301 XColor fg, bg;302 XCursor xc;303 Pixmap xsrc, xmask;304 int i;305 uchar src[2*16], mask[2*16];307 if(c == nil){308 xcursorarrow();309 return;310 }311 for(i=0; i<2*16; i++){312 src[i] = revbyte(c->set[i]);313 mask[i] = revbyte(c->set[i] | c->clr[i]);314 }316 fg = _x.map[0];317 bg = _x.map[255];318 xsrc = XCreateBitmapFromData(_x.display, _x.drawable, src, 16, 16);319 xmask = XCreateBitmapFromData(_x.display, _x.drawable, mask, 16, 16);320 xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y);321 if(xc != 0) {322 XDefineCursor(_x.display, _x.drawable, xc);323 if(_x.cursor != 0)324 XFreeCursor(_x.display, _x.cursor);325 _x.cursor = xc;326 }327 XFreePixmap(_x.display, xsrc);328 XFreePixmap(_x.display, xmask);329 XFlush(_x.display);330 }332 struct {333 char buf[SnarfSize];334 QLock lk;335 } clip;337 char*338 _xgetsnarf(XDisplay *xd)339 {340 uchar *data, *xdata;341 Atom clipboard, type, prop;342 ulong len, lastlen, dummy;343 int fmt, i;344 XWindow w;346 qlock(&clip.lk);347 /*348 * Is there a primary selection (highlighted text in an xterm)?349 */350 clipboard = XA_PRIMARY;351 w = XGetSelectionOwner(xd, XA_PRIMARY);352 if(w == _x.drawable){353 mine:354 data = (uchar*)strdup(clip.buf);355 goto out;356 }358 /*359 * If not, is there a clipboard selection?360 */361 if(w == None && _x.clipboard != None){362 clipboard = _x.clipboard;363 w = XGetSelectionOwner(xd, _x.clipboard);364 if(w == _x.drawable)365 goto mine;366 }368 /*369 * If not, give up.370 */371 if(w == None){372 data = nil;373 goto out;374 }376 /*377 * We should be waiting for SelectionNotify here, but it might never378 * come, and we have no way to time out. Instead, we will clear379 * local property #1, request our buddy to fill it in for us, and poll380 * until he's done or we get tired of waiting.381 *382 * We should try to go for _x.utf8string instead of XA_STRING,383 * but that would add to the polling.384 */385 prop = 1;386 XChangeProperty(xd, _x.drawable, prop, XA_STRING, 8, PropModeReplace, (uchar*)"", 0);387 XConvertSelection(xd, clipboard, XA_STRING, prop, _x.drawable, CurrentTime);388 XFlush(xd);389 lastlen = 0;390 for(i=0; i<10 || (lastlen!=0 && i<30); i++){391 usleep(100*1000);392 XGetWindowProperty(xd, _x.drawable, prop, 0, 0, 0, AnyPropertyType,393 &type, &fmt, &dummy, &len, &data);394 if(lastlen == len && len > 0)395 break;396 lastlen = len;397 }398 if(i == 10){399 data = nil;400 goto out;401 }402 /* get the property */403 data = nil;404 XGetWindowProperty(xd, _x.drawable, prop, 0, SnarfSize/sizeof(ulong), 0,405 AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);406 if((type != XA_STRING && type != _x.utf8string) || len == 0){407 if(xdata)408 XFree(xdata);409 data = nil;410 }else{411 if(xdata){412 data = strdup((char*)xdata);413 XFree(xdata);414 }else415 data = nil;416 }417 out:418 qunlock(&clip.lk);419 return data;420 }422 void423 _xputsnarf(XDisplay *xd, char *data)424 {425 XButtonEvent e;427 if(strlen(data) >= SnarfSize)428 return;429 qlock(&clip.lk);430 strcpy(clip.buf, data);432 /* leave note for mouse proc to assert selection ownership */433 _x.putsnarf++;435 /* send mouse a fake event so snarf is announced */436 memset(&e, 0, sizeof e);437 e.type = ButtonPress;438 e.window = _x.drawable;439 e.state = ~0;440 e.button = ~0;441 XSendEvent(xd, _x.drawable, True, ButtonPressMask, (XEvent*)&e);442 XFlush(xd);444 qunlock(&clip.lk);445 }447 int448 _xselect(XEvent *e, XDisplay *xd)449 {450 char *name;451 XEvent r;452 XSelectionRequestEvent *xe;453 Atom a[4];455 memset(&r, 0, sizeof r);456 xe = (XSelectionRequestEvent*)e;457 if(1) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d\n",458 xe->target, xe->requestor, xe->property, xe->selection);459 r.xselection.property = xe->property;460 if(xe->target == _x.targets){461 a[0] = XA_STRING;462 a[1] = _x.utf8string;463 a[2] = _x.text;464 a[3] = _x.compoundtext;466 XChangeProperty(xd, xe->requestor, xe->property, xe->target,467 8, PropModeReplace, (uchar*)a, sizeof a);468 }else if(xe->target == XA_STRING || xe->target == _x.utf8string || xe->target == _x.text || xe->target == _x.compoundtext){469 /* if the target is STRING we're supposed to reply with Latin1 XXX */470 qlock(&clip.lk);471 XChangeProperty(xd, xe->requestor, xe->property, xe->target,472 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));473 qunlock(&clip.lk);474 }else{475 name = XGetAtomName(xd, xe->target);476 fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);477 r.xselection.property = None;478 }480 r.xselection.display = xe->display;481 /* r.xselection.property filled above */482 r.xselection.target = xe->target;483 r.xselection.type = SelectionNotify;484 r.xselection.requestor = xe->requestor;485 r.xselection.time = xe->time;486 r.xselection.send_event = True;487 r.xselection.selection = xe->selection;488 XSendEvent(xd, xe->requestor, False, 0, &r);489 XFlush(xd);490 return 0;491 }493 void494 putsnarf(char *data)495 {496 _xputsnarf(_x.snarfcon, data);497 }499 char*500 getsnarf(void)501 {502 return _xgetsnarf(_x.snarfcon);503 }