1 50923426 2020-01-13 rsc #include <u.h>
2 50923426 2020-01-13 rsc #include "x11-inc.h"
3 50923426 2020-01-13 rsc #include "x11-keysym2ucs.h"
4 50923426 2020-01-13 rsc #include <errno.h>
5 50923426 2020-01-13 rsc #include <libc.h>
6 50923426 2020-01-13 rsc #include <draw.h>
7 50923426 2020-01-13 rsc #include <memdraw.h>
8 50923426 2020-01-13 rsc #include <memlayer.h>
9 50923426 2020-01-13 rsc #include <keyboard.h>
10 50923426 2020-01-13 rsc #include <mouse.h>
11 50923426 2020-01-13 rsc #include <cursor.h>
12 50923426 2020-01-13 rsc #include <thread.h>
13 50923426 2020-01-13 rsc #include "x11-memdraw.h"
14 50923426 2020-01-13 rsc #include "devdraw.h"
18 50923426 2020-01-13 rsc static void plan9cmap(void);
19 50923426 2020-01-13 rsc static int setupcmap(XWindow);
20 50923426 2020-01-13 rsc static XGC xgc(XDrawable, int, int);
21 50923426 2020-01-13 rsc #define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
23 50923426 2020-01-13 rsc #define MouseMask (\
24 50923426 2020-01-13 rsc ButtonPressMask|\
25 50923426 2020-01-13 rsc ButtonReleaseMask|\
26 50923426 2020-01-13 rsc PointerMotionMask|\
27 50923426 2020-01-13 rsc Button1MotionMask|\
28 50923426 2020-01-13 rsc Button2MotionMask|\
29 50923426 2020-01-13 rsc Button3MotionMask)
33 50923426 2020-01-13 rsc static void runxevent(XEvent *xev);
34 50923426 2020-01-13 rsc static int _xconfigure(Xwin *w, XEvent *e);
35 50923426 2020-01-13 rsc static int _xdestroy(Xwin *w, XEvent *e);
36 50923426 2020-01-13 rsc static void _xexpose(Xwin *w, XEvent *e);
37 50923426 2020-01-13 rsc static int _xreplacescreenimage(Client *client);
38 50923426 2020-01-13 rsc static int _xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m);
39 50923426 2020-01-13 rsc static void _xmovewindow(Xwin *w, Rectangle r);
40 50923426 2020-01-13 rsc static int _xtoplan9kbd(XEvent *e);
41 50923426 2020-01-13 rsc static int _xselect(XEvent *e);
43 84167be4 2020-05-18 rsc static void rpc_resizeimg(Client*);
44 84167be4 2020-05-18 rsc static void rpc_resizewindow(Client*, Rectangle);
45 84167be4 2020-05-18 rsc static void rpc_setcursor(Client*, Cursor*, Cursor2*);
46 84167be4 2020-05-18 rsc static void rpc_setlabel(Client*, char*);
47 84167be4 2020-05-18 rsc static void rpc_setmouse(Client*, Point);
48 84167be4 2020-05-18 rsc static void rpc_topwin(Client*);
49 84167be4 2020-05-18 rsc static void rpc_bouncemouse(Client*, Mouse);
50 84167be4 2020-05-18 rsc static void rpc_flush(Client*, Rectangle);
52 84167be4 2020-05-18 rsc static ClientImpl x11impl = {
53 84167be4 2020-05-18 rsc rpc_resizeimg,
54 84167be4 2020-05-18 rsc rpc_resizewindow,
55 84167be4 2020-05-18 rsc rpc_setcursor,
56 84167be4 2020-05-18 rsc rpc_setlabel,
57 84167be4 2020-05-18 rsc rpc_setmouse,
59 84167be4 2020-05-18 rsc rpc_bouncemouse,
64 50923426 2020-01-13 rsc newxwin(Client *c)
68 50923426 2020-01-13 rsc w = mallocz(sizeof *w, 1);
70 50923426 2020-01-13 rsc sysfatal("out of memory");
71 50923426 2020-01-13 rsc w->client = c;
72 50923426 2020-01-13 rsc w->next = _x.windows;
73 50923426 2020-01-13 rsc _x.windows = w;
74 84167be4 2020-05-18 rsc c->impl = &x11impl;
80 50923426 2020-01-13 rsc findxwin(XDrawable d)
82 50923426 2020-01-13 rsc Xwin *w, **l;
84 50923426 2020-01-13 rsc for(l=&_x.windows; (w=*l) != nil; l=&w->next) {
85 50923426 2020-01-13 rsc if(w->drawable == d) {
86 50923426 2020-01-13 rsc /* move to front */
87 50923426 2020-01-13 rsc *l = w->next;
88 50923426 2020-01-13 rsc w->next = _x.windows;
89 50923426 2020-01-13 rsc _x.windows = w;
97 50923426 2020-01-13 rsc xerror(XDisplay *d, XErrorEvent *e)
99 50923426 2020-01-13 rsc char buf[200];
101 50923426 2020-01-13 rsc if(e->request_code == 42) /* XSetInputFocus */
103 50923426 2020-01-13 rsc if(e->request_code == 18) /* XChangeProperty */
106 50923426 2020-01-13 rsc * BadDrawable happens in apps that get resized a LOT,
107 50923426 2020-01-13 rsc * e.g. when KDE is configured to resize continuously
108 50923426 2020-01-13 rsc * during a window drag.
110 50923426 2020-01-13 rsc if(e->error_code == 9) /* BadDrawable */
113 50923426 2020-01-13 rsc fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
114 50923426 2020-01-13 rsc e->error_code, e->request_code, e->minor_code, d);
115 50923426 2020-01-13 rsc XGetErrorText(d, e->error_code, buf, sizeof buf);
116 50923426 2020-01-13 rsc fprint(2, "%s\n", buf);
121 50923426 2020-01-13 rsc xioerror(XDisplay *d)
123 50923426 2020-01-13 rsc /*print("X I/O error\n"); */
125 50923426 2020-01-13 rsc /*sysfatal("X I/O error\n");*/
130 50923426 2020-01-13 rsc static void xloop(void);
132 50923426 2020-01-13 rsc static QLock xlk;
137 50923426 2020-01-13 rsc qlock(&xlk);
141 50923426 2020-01-13 rsc xunlock(void)
143 50923426 2020-01-13 rsc qunlock(&xlk);
147 50923426 2020-01-13 rsc gfx_main(void)
150 50923426 2020-01-13 rsc int i, n, xrootid;
151 50923426 2020-01-13 rsc XPixmapFormatValues *pfmt;
152 50923426 2020-01-13 rsc XScreen *xscreen;
153 50923426 2020-01-13 rsc XVisualInfo xvi;
154 50923426 2020-01-13 rsc XWindow xrootwin;
157 50923426 2020-01-13 rsc if(XInitThreads() == 0)
158 50923426 2020-01-13 rsc sysfatal("XInitThread: %r");
162 50923426 2020-01-13 rsc * Connect to X server.
164 50923426 2020-01-13 rsc _x.display = XOpenDisplay(NULL);
165 50923426 2020-01-13 rsc if(_x.display == nil){
166 50923426 2020-01-13 rsc disp = getenv("DISPLAY");
167 50923426 2020-01-13 rsc werrstr("XOpenDisplay %s: %r", disp ? disp : ":0");
169 50923426 2020-01-13 rsc sysfatal("%r");
171 50923426 2020-01-13 rsc _x.fd = ConnectionNumber(_x.display);
172 50923426 2020-01-13 rsc XSetErrorHandler(xerror);
173 50923426 2020-01-13 rsc XSetIOErrorHandler(xioerror);
174 50923426 2020-01-13 rsc xrootid = DefaultScreen(_x.display);
175 50923426 2020-01-13 rsc xrootwin = DefaultRootWindow(_x.display);
178 50923426 2020-01-13 rsc * Figure out underlying screen format.
180 50923426 2020-01-13 rsc if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
181 50923426 2020-01-13 rsc || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
182 50923426 2020-01-13 rsc _x.vis = xvi.visual;
183 50923426 2020-01-13 rsc _x.depth = 24;
186 50923426 2020-01-13 rsc if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
187 50923426 2020-01-13 rsc || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
188 50923426 2020-01-13 rsc _x.vis = xvi.visual;
189 50923426 2020-01-13 rsc _x.depth = 16;
192 50923426 2020-01-13 rsc if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
193 50923426 2020-01-13 rsc || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
194 50923426 2020-01-13 rsc _x.vis = xvi.visual;
195 50923426 2020-01-13 rsc _x.depth = 15;
198 50923426 2020-01-13 rsc if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
199 50923426 2020-01-13 rsc || XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){
200 50923426 2020-01-13 rsc if(_x.depth > 8){
201 50923426 2020-01-13 rsc werrstr("can't deal with colormapped depth %d screens",
205 50923426 2020-01-13 rsc _x.vis = xvi.visual;
206 50923426 2020-01-13 rsc _x.depth = 8;
209 50923426 2020-01-13 rsc _x.depth = DefaultDepth(_x.display, xrootid);
210 50923426 2020-01-13 rsc if(_x.depth != 8){
211 50923426 2020-01-13 rsc werrstr("can't understand depth %d screen", _x.depth);
214 50923426 2020-01-13 rsc _x.vis = DefaultVisual(_x.display, xrootid);
217 50923426 2020-01-13 rsc if(DefaultDepth(_x.display, xrootid) == _x.depth)
218 50923426 2020-01-13 rsc _x.usetable = 1;
221 50923426 2020-01-13 rsc * _x.depth is only the number of significant pixel bits,
222 50923426 2020-01-13 rsc * not the total number of pixel bits. We need to walk the
223 50923426 2020-01-13 rsc * display list to find how many actual bits are used
224 50923426 2020-01-13 rsc * per pixel.
226 50923426 2020-01-13 rsc _x.chan = 0;
227 50923426 2020-01-13 rsc pfmt = XListPixmapFormats(_x.display, &n);
228 50923426 2020-01-13 rsc for(i=0; i<n; i++){
229 50923426 2020-01-13 rsc if(pfmt[i].depth == _x.depth){
230 50923426 2020-01-13 rsc switch(pfmt[i].bits_per_pixel){
231 50923426 2020-01-13 rsc case 1: /* untested */
232 50923426 2020-01-13 rsc _x.chan = GREY1;
234 50923426 2020-01-13 rsc case 2: /* untested */
235 50923426 2020-01-13 rsc _x.chan = GREY2;
237 50923426 2020-01-13 rsc case 4: /* untested */
238 50923426 2020-01-13 rsc _x.chan = GREY4;
241 50923426 2020-01-13 rsc _x.chan = CMAP8;
244 50923426 2020-01-13 rsc _x.chan = RGB15;
246 50923426 2020-01-13 rsc case 16: /* how to tell RGB15? */
247 50923426 2020-01-13 rsc _x.chan = RGB16;
249 50923426 2020-01-13 rsc case 24: /* untested (impossible?) */
250 50923426 2020-01-13 rsc _x.chan = RGB24;
253 50923426 2020-01-13 rsc _x.chan = XRGB32;
258 50923426 2020-01-13 rsc XFree(pfmt);
259 50923426 2020-01-13 rsc if(_x.chan == 0){
260 50923426 2020-01-13 rsc werrstr("could not determine screen pixel format");
265 50923426 2020-01-13 rsc * Set up color map if necessary.
267 50923426 2020-01-13 rsc xscreen = DefaultScreenOfDisplay(_x.display);
268 50923426 2020-01-13 rsc _x.cmap = DefaultColormapOfScreen(xscreen);
269 50923426 2020-01-13 rsc if(_x.vis->class != StaticColor){
270 50923426 2020-01-13 rsc plan9cmap();
271 50923426 2020-01-13 rsc setupcmap(xrootwin);
273 50923426 2020-01-13 rsc gfx_started();
277 50923426 2020-01-13 rsc XCloseDisplay(_x.display);
278 50923426 2020-01-13 rsc sysfatal("%r");
284 50923426 2020-01-13 rsc fd_set rd, wr, xx;
285 50923426 2020-01-13 rsc XEvent event;
288 50923426 2020-01-13 rsc _x.fd = ConnectionNumber(_x.display);
290 50923426 2020-01-13 rsc FD_ZERO(&rd);
291 50923426 2020-01-13 rsc FD_ZERO(&wr);
292 50923426 2020-01-13 rsc FD_ZERO(&xx);
293 50923426 2020-01-13 rsc FD_SET(_x.fd, &rd);
294 50923426 2020-01-13 rsc FD_SET(_x.fd, &xx);
295 50923426 2020-01-13 rsc if(_x.windows != nil)
296 50923426 2020-01-13 rsc XSelectInput(_x.display, _x.windows->drawable, Mask); // TODO: when is this needed?
297 50923426 2020-01-13 rsc XFlush(_x.display);
301 50923426 2020-01-13 rsc if(select(_x.fd+1, &rd, &wr, &xx, nil) < 0) {
302 50923426 2020-01-13 rsc if(errno == EINTR)
304 50923426 2020-01-13 rsc sysfatal("select: %r"); // TODO: quiet exit?
308 50923426 2020-01-13 rsc while(XPending(_x.display)) {
309 50923426 2020-01-13 rsc XNextEvent(_x.display, &event);
310 50923426 2020-01-13 rsc runxevent(&event);
315 85bfd19a 2022-07-26 crossd static int kcodecontrol, kcodealt, kcodeshift;
318 50923426 2020-01-13 rsc * Handle an incoming X event.
321 50923426 2020-01-13 rsc runxevent(XEvent *xev)
324 85bfd19a 2022-07-26 crossd int modp;
326 50923426 2020-01-13 rsc static Mouse m;
327 50923426 2020-01-13 rsc XButtonEvent *be;
328 50923426 2020-01-13 rsc XKeyEvent *ke;
331 85bfd19a 2022-07-26 crossd modp = 0;
333 50923426 2020-01-13 rsc #ifdef SHOWEVENT
334 50923426 2020-01-13 rsc static int first = 1;
336 50923426 2020-01-13 rsc dup(create("/tmp/devdraw.out", OWRITE, 0666), 1);
337 50923426 2020-01-13 rsc setbuf(stdout, 0);
342 50923426 2020-01-13 rsc if(xev == 0)
345 50923426 2020-01-13 rsc #ifdef SHOWEVENT
346 50923426 2020-01-13 rsc print("\n");
347 50923426 2020-01-13 rsc ShowEvent(xev);
351 50923426 2020-01-13 rsc switch(xev->type){
352 50923426 2020-01-13 rsc case Expose:
353 50923426 2020-01-13 rsc w = findxwin(((XExposeEvent*)xev)->window);
355 50923426 2020-01-13 rsc case DestroyNotify:
356 50923426 2020-01-13 rsc w = findxwin(((XDestroyWindowEvent*)xev)->window);
358 50923426 2020-01-13 rsc case ConfigureNotify:
359 50923426 2020-01-13 rsc w = findxwin(((XConfigureEvent*)xev)->window);
361 50923426 2020-01-13 rsc case ButtonPress:
362 50923426 2020-01-13 rsc case ButtonRelease:
363 50923426 2020-01-13 rsc w = findxwin(((XButtonEvent*)xev)->window);
365 50923426 2020-01-13 rsc case MotionNotify:
366 50923426 2020-01-13 rsc w = findxwin(((XMotionEvent*)xev)->window);
368 50923426 2020-01-13 rsc case KeyRelease:
369 50923426 2020-01-13 rsc case KeyPress:
370 50923426 2020-01-13 rsc w = findxwin(((XKeyEvent*)xev)->window);
372 50923426 2020-01-13 rsc case FocusOut:
373 50923426 2020-01-13 rsc w = findxwin(((XFocusChangeEvent*)xev)->window);
376 50923426 2020-01-13 rsc if(w == nil)
377 50923426 2020-01-13 rsc w = _x.windows;
379 50923426 2020-01-13 rsc switch(xev->type){
380 50923426 2020-01-13 rsc case Expose:
381 50923426 2020-01-13 rsc _xexpose(w, xev);
384 50923426 2020-01-13 rsc case DestroyNotify:
385 50923426 2020-01-13 rsc if(_xdestroy(w, xev))
386 50923426 2020-01-13 rsc threadexitsall(nil);
389 50923426 2020-01-13 rsc case ConfigureNotify:
390 50923426 2020-01-13 rsc if(_xconfigure(w, xev))
391 50923426 2020-01-13 rsc _xreplacescreenimage(w->client);
394 50923426 2020-01-13 rsc case ButtonPress:
395 50923426 2020-01-13 rsc be = (XButtonEvent*)xev;
396 50923426 2020-01-13 rsc if(be->button == 1) {
397 50923426 2020-01-13 rsc if(_x.kstate & ControlMask)
398 50923426 2020-01-13 rsc be->button = 2;
399 50923426 2020-01-13 rsc else if(_x.kstate & Mod1Mask)
400 50923426 2020-01-13 rsc be->button = 3;
402 50923426 2020-01-13 rsc // fall through
403 50923426 2020-01-13 rsc case ButtonRelease:
404 50923426 2020-01-13 rsc _x.altdown = 0;
405 50923426 2020-01-13 rsc // fall through
406 50923426 2020-01-13 rsc case MotionNotify:
407 50923426 2020-01-13 rsc if(_xtoplan9mouse(w, xev, &m) < 0)
409 50923426 2020-01-13 rsc gfx_mousetrack(w->client, m.xy.x, m.xy.y, m.buttons|_x.kbuttons, m.msec);
412 50923426 2020-01-13 rsc case KeyRelease:
413 50923426 2020-01-13 rsc case KeyPress:
414 50923426 2020-01-13 rsc ke = (XKeyEvent*)xev;
415 50923426 2020-01-13 rsc XLookupString(ke, NULL, 0, &k, NULL);
416 50923426 2020-01-13 rsc c = ke->state;
418 50923426 2020-01-13 rsc case XK_Alt_L:
419 50923426 2020-01-13 rsc case XK_Meta_L: /* Shift Alt on PCs */
420 50923426 2020-01-13 rsc case XK_Alt_R:
421 50923426 2020-01-13 rsc case XK_Meta_R: /* Shift Alt on PCs */
422 50923426 2020-01-13 rsc case XK_Multi_key:
423 50923426 2020-01-13 rsc if(xev->type == KeyPress)
424 50923426 2020-01-13 rsc _x.altdown = 1;
425 50923426 2020-01-13 rsc else if(_x.altdown) {
426 50923426 2020-01-13 rsc _x.altdown = 0;
427 50923426 2020-01-13 rsc gfx_keystroke(w->client, Kalt);
432 85bfd19a 2022-07-26 crossd if(xev->type == KeyPress)
433 85bfd19a 2022-07-26 crossd switch(k) {
434 85bfd19a 2022-07-26 crossd case XK_Control_L:
435 85bfd19a 2022-07-26 crossd case XK_Control_R:
436 85bfd19a 2022-07-26 crossd kcodecontrol = ke->keycode;
437 50923426 2020-01-13 rsc c |= ControlMask;
438 85bfd19a 2022-07-26 crossd modp = 1;
440 85bfd19a 2022-07-26 crossd case XK_Alt_L:
441 85bfd19a 2022-07-26 crossd case XK_Alt_R:
442 85bfd19a 2022-07-26 crossd kcodealt = ke->keycode;
443 85bfd19a 2022-07-26 crossd // fall through
444 85bfd19a 2022-07-26 crossd case XK_Shift_L:
445 85bfd19a 2022-07-26 crossd case XK_Shift_R:
446 85bfd19a 2022-07-26 crossd kcodeshift = ke->keycode;
447 85bfd19a 2022-07-26 crossd c |= Mod1Mask;
448 85bfd19a 2022-07-26 crossd modp = 1;
451 85bfd19a 2022-07-26 crossd if(ke->keycode == kcodecontrol){
452 85bfd19a 2022-07-26 crossd c &= ~ControlMask;
453 85bfd19a 2022-07-26 crossd modp = 1;
454 85bfd19a 2022-07-26 crossd } else if(ke->keycode == kcodealt || ke->keycode == kcodeshift){
455 50923426 2020-01-13 rsc c &= ~Mod1Mask;
456 85bfd19a 2022-07-26 crossd modp = 1;
459 85bfd19a 2022-07-26 crossd if(modp){
460 50923426 2020-01-13 rsc _x.kstate = c;
461 50923426 2020-01-13 rsc if(m.buttons || _x.kbuttons) {
462 50923426 2020-01-13 rsc _x.altdown = 0; // used alt
463 50923426 2020-01-13 rsc _x.kbuttons = 0;
464 50923426 2020-01-13 rsc if(c & ControlMask)
465 50923426 2020-01-13 rsc _x.kbuttons |= 2;
466 50923426 2020-01-13 rsc if(c & Mod1Mask)
467 50923426 2020-01-13 rsc _x.kbuttons |= 4;
468 50923426 2020-01-13 rsc gfx_mousetrack(w->client, m.xy.x, m.xy.y, m.buttons|_x.kbuttons, m.msec);
470 85bfd19a 2022-07-26 crossd modp = 0;
473 50923426 2020-01-13 rsc if(xev->type != KeyPress)
475 50923426 2020-01-13 rsc if(k == XK_F11){
476 50923426 2020-01-13 rsc w->fullscreen = !w->fullscreen;
477 50923426 2020-01-13 rsc _xmovewindow(w, w->fullscreen ? w->screenrect : w->windowrect);
480 50923426 2020-01-13 rsc if((c = _xtoplan9kbd(xev)) < 0)
482 50923426 2020-01-13 rsc gfx_keystroke(w->client, c);
485 50923426 2020-01-13 rsc case FocusOut:
487 50923426 2020-01-13 rsc * Some key combinations (e.g. Alt-Tab) can cause us
488 50923426 2020-01-13 rsc * to see the key down event without the key up event,
489 50923426 2020-01-13 rsc * so clear out the keyboard state when we lose the focus.
491 50923426 2020-01-13 rsc _x.kstate = 0;
492 50923426 2020-01-13 rsc _x.altdown = 0;
493 50923426 2020-01-13 rsc gfx_abortcompose(w->client);
496 50923426 2020-01-13 rsc case SelectionRequest:
497 50923426 2020-01-13 rsc _xselect(xev);
503 50923426 2020-01-13 rsc static Memimage*
504 50923426 2020-01-13 rsc xattach(Client *client, char *label, char *winsize)
506 50923426 2020-01-13 rsc char *argv[2];
507 50923426 2020-01-13 rsc int havemin, height, mask, width, x, y;
508 50923426 2020-01-13 rsc Rectangle r;
509 50923426 2020-01-13 rsc XClassHint classhint;
510 50923426 2020-01-13 rsc XDrawable pmid;
511 50923426 2020-01-13 rsc XScreen *xscreen;
512 50923426 2020-01-13 rsc XSetWindowAttributes attr;
513 50923426 2020-01-13 rsc XSizeHints normalhint;
514 50923426 2020-01-13 rsc XTextProperty name;
515 50923426 2020-01-13 rsc XWindow xrootwin;
516 50923426 2020-01-13 rsc XWindowAttributes wattr;
517 50923426 2020-01-13 rsc XWMHints hint;
518 50923426 2020-01-13 rsc Atom atoms[2];
521 50923426 2020-01-13 rsc USED(client);
522 50923426 2020-01-13 rsc xscreen = DefaultScreenOfDisplay(_x.display);
523 50923426 2020-01-13 rsc xrootwin = DefaultRootWindow(_x.display);
526 50923426 2020-01-13 rsc * We get to choose the initial rectangle size.
527 50923426 2020-01-13 rsc * This is arbitrary. In theory we should read the
528 50923426 2020-01-13 rsc * command line and allow the traditional X options.
533 50923426 2020-01-13 rsc if(winsize && winsize[0]){
534 50923426 2020-01-13 rsc if(parsewinsize(winsize, &r, &havemin) < 0)
535 50923426 2020-01-13 rsc sysfatal("%r");
538 50923426 2020-01-13 rsc * Parse the various X resources. Thanks to Peter Canning.
540 50923426 2020-01-13 rsc char *screen_resources, *display_resources, *geom,
541 50923426 2020-01-13 rsc *geomrestype, *home, *file, *dpitype;
542 50923426 2020-01-13 rsc XrmDatabase database;
543 50923426 2020-01-13 rsc XrmValue geomres, dpires;
545 50923426 2020-01-13 rsc database = XrmGetDatabase(_x.display);
546 50923426 2020-01-13 rsc screen_resources = XScreenResourceString(xscreen);
547 50923426 2020-01-13 rsc if(screen_resources != nil){
548 50923426 2020-01-13 rsc XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False);
549 50923426 2020-01-13 rsc XFree(screen_resources);
552 50923426 2020-01-13 rsc display_resources = XResourceManagerString(_x.display);
553 50923426 2020-01-13 rsc if(display_resources == nil){
554 50923426 2020-01-13 rsc home = getenv("HOME");
555 50923426 2020-01-13 rsc if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){
556 50923426 2020-01-13 rsc XrmCombineFileDatabase(file, &database, False);
561 50923426 2020-01-13 rsc XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False);
563 50923426 2020-01-13 rsc if (XrmGetResource(database, "Xft.dpi", "String", &dpitype, &dpires) == True) {
564 50923426 2020-01-13 rsc if (dpires.addr) {
565 50923426 2020-01-13 rsc client->displaydpi = atoi(dpires.addr);
568 50923426 2020-01-13 rsc geom = smprint("%s.geometry", label);
569 50923426 2020-01-13 rsc if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres))
570 50923426 2020-01-13 rsc mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height);
571 50923426 2020-01-13 rsc XrmDestroyDatabase(database);
574 50923426 2020-01-13 rsc if((mask & WidthValue) && (mask & HeightValue)){
575 50923426 2020-01-13 rsc r = Rect(0, 0, width, height);
577 50923426 2020-01-13 rsc r = Rect(0, 0, WidthOfScreen(xscreen)*3/4,
578 50923426 2020-01-13 rsc HeightOfScreen(xscreen)*3/4);
579 50923426 2020-01-13 rsc if(Dx(r) > Dy(r)*3/2)
580 50923426 2020-01-13 rsc r.max.x = r.min.x + Dy(r)*3/2;
581 50923426 2020-01-13 rsc if(Dy(r) > Dx(r)*3/2)
582 50923426 2020-01-13 rsc r.max.y = r.min.y + Dx(r)*3/2;
584 50923426 2020-01-13 rsc if(mask & XNegative){
585 50923426 2020-01-13 rsc x += WidthOfScreen(xscreen);
587 50923426 2020-01-13 rsc if(mask & YNegative){
588 50923426 2020-01-13 rsc y += HeightOfScreen(xscreen);
590 50923426 2020-01-13 rsc havemin = 0;
592 50923426 2020-01-13 rsc w = newxwin(client);
594 50923426 2020-01-13 rsc memset(&attr, 0, sizeof attr);
595 50923426 2020-01-13 rsc attr.colormap = _x.cmap;
596 50923426 2020-01-13 rsc attr.background_pixel = ~0;
597 50923426 2020-01-13 rsc attr.border_pixel = 0;
598 50923426 2020-01-13 rsc w->drawable = XCreateWindow(
599 50923426 2020-01-13 rsc _x.display, /* display */
600 50923426 2020-01-13 rsc xrootwin, /* parent */
603 50923426 2020-01-13 rsc Dx(r), /* width */
604 50923426 2020-01-13 rsc Dy(r), /* height */
605 50923426 2020-01-13 rsc 0, /* border width */
606 50923426 2020-01-13 rsc _x.depth, /* depth */
607 50923426 2020-01-13 rsc InputOutput, /* class */
608 50923426 2020-01-13 rsc _x.vis, /* visual */
609 50923426 2020-01-13 rsc /* valuemask */
610 50923426 2020-01-13 rsc CWBackPixel|CWBorderPixel|CWColormap,
611 50923426 2020-01-13 rsc &attr /* attributes (the above aren't?!) */
615 50923426 2020-01-13 rsc * Label and other properties required by ICCCCM.
617 50923426 2020-01-13 rsc memset(&name, 0, sizeof name);
618 50923426 2020-01-13 rsc if(label == nil)
619 50923426 2020-01-13 rsc label = "pjw-face-here";
620 50923426 2020-01-13 rsc name.value = (uchar*)label;
621 50923426 2020-01-13 rsc name.encoding = XA_STRING;
622 50923426 2020-01-13 rsc name.format = 8;
623 50923426 2020-01-13 rsc name.nitems = strlen((char*)name.value);
625 50923426 2020-01-13 rsc memset(&normalhint, 0, sizeof normalhint);
626 50923426 2020-01-13 rsc normalhint.flags = PSize|PMaxSize;
627 50923426 2020-01-13 rsc if(winsize && winsize[0]){
628 50923426 2020-01-13 rsc normalhint.flags &= ~PSize;
629 50923426 2020-01-13 rsc normalhint.flags |= USSize;
630 50923426 2020-01-13 rsc normalhint.width = Dx(r);
631 50923426 2020-01-13 rsc normalhint.height = Dy(r);
633 50923426 2020-01-13 rsc if((mask & WidthValue) && (mask & HeightValue)){
634 50923426 2020-01-13 rsc normalhint.flags &= ~PSize;
635 50923426 2020-01-13 rsc normalhint.flags |= USSize;
636 50923426 2020-01-13 rsc normalhint.width = width;
637 50923426 2020-01-13 rsc normalhint.height = height;
639 50923426 2020-01-13 rsc if((mask & WidthValue) && (mask & HeightValue)){
640 50923426 2020-01-13 rsc normalhint.flags |= USPosition;
641 50923426 2020-01-13 rsc normalhint.x = x;
642 50923426 2020-01-13 rsc normalhint.y = y;
646 50923426 2020-01-13 rsc normalhint.max_width = WidthOfScreen(xscreen);
647 50923426 2020-01-13 rsc normalhint.max_height = HeightOfScreen(xscreen);
649 50923426 2020-01-13 rsc memset(&hint, 0, sizeof hint);
650 50923426 2020-01-13 rsc hint.flags = InputHint|StateHint;
651 50923426 2020-01-13 rsc hint.input = 1;
652 50923426 2020-01-13 rsc hint.initial_state = NormalState;
654 50923426 2020-01-13 rsc memset(&classhint, 0, sizeof classhint);
655 50923426 2020-01-13 rsc classhint.res_name = label;
656 50923426 2020-01-13 rsc classhint.res_class = label;
658 50923426 2020-01-13 rsc argv[0] = label;
659 50923426 2020-01-13 rsc argv[1] = nil;
661 50923426 2020-01-13 rsc XSetWMProperties(
662 50923426 2020-01-13 rsc _x.display, /* display */
663 50923426 2020-01-13 rsc w->drawable, /* window */
664 50923426 2020-01-13 rsc &name, /* XA_WM_NAME property */
665 50923426 2020-01-13 rsc &name, /* XA_WM_ICON_NAME property */
666 50923426 2020-01-13 rsc argv, /* XA_WM_COMMAND */
667 50923426 2020-01-13 rsc 1, /* argc */
668 50923426 2020-01-13 rsc &normalhint, /* XA_WM_NORMAL_HINTS */
669 50923426 2020-01-13 rsc &hint, /* XA_WM_HINTS */
670 50923426 2020-01-13 rsc &classhint /* XA_WM_CLASSHINTS */
672 50923426 2020-01-13 rsc XFlush(_x.display);
674 50923426 2020-01-13 rsc if(havemin){
675 50923426 2020-01-13 rsc XWindowChanges ch;
677 50923426 2020-01-13 rsc memset(&ch, 0, sizeof ch);
678 50923426 2020-01-13 rsc ch.x = r.min.x;
679 50923426 2020-01-13 rsc ch.y = r.min.y;
680 50923426 2020-01-13 rsc XConfigureWindow(_x.display, w->drawable, CWX|CWY, &ch);
682 50923426 2020-01-13 rsc * Must pretend origin is 0,0 for X.
684 50923426 2020-01-13 rsc r = Rect(0,0,Dx(r),Dy(r));
687 50923426 2020-01-13 rsc * Look up clipboard atom.
689 50923426 2020-01-13 rsc if(_x.clipboard == 0) {
690 50923426 2020-01-13 rsc _x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False);
691 50923426 2020-01-13 rsc _x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False);
692 50923426 2020-01-13 rsc _x.targets = XInternAtom(_x.display, "TARGETS", False);
693 50923426 2020-01-13 rsc _x.text = XInternAtom(_x.display, "TEXT", False);
694 50923426 2020-01-13 rsc _x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False);
695 50923426 2020-01-13 rsc _x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False);
696 50923426 2020-01-13 rsc _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False);
697 50923426 2020-01-13 rsc _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False);
700 50923426 2020-01-13 rsc atoms[0] = _x.takefocus;
701 50923426 2020-01-13 rsc atoms[1] = _x.losefocus;
702 50923426 2020-01-13 rsc XChangeProperty(_x.display, w->drawable, _x.wmprotos, XA_ATOM, 32,
703 50923426 2020-01-13 rsc PropModeReplace, (uchar*)atoms, 2);
706 50923426 2020-01-13 rsc * Put the window on the screen, check to see what size we actually got.
708 50923426 2020-01-13 rsc XMapWindow(_x.display, w->drawable);
709 50923426 2020-01-13 rsc XSync(_x.display, False);
711 50923426 2020-01-13 rsc if(!XGetWindowAttributes(_x.display, w->drawable, &wattr))
712 50923426 2020-01-13 rsc fprint(2, "XGetWindowAttributes failed\n");
713 50923426 2020-01-13 rsc else if(wattr.width && wattr.height){
714 50923426 2020-01-13 rsc if(wattr.width != Dx(r) || wattr.height != Dy(r)){
715 50923426 2020-01-13 rsc r.max.x = wattr.width;
716 50923426 2020-01-13 rsc r.max.y = wattr.height;
719 50923426 2020-01-13 rsc fprint(2, "XGetWindowAttributes: bad attrs\n");
720 fe2b2de9 2020-01-15 rsc w->screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen));
721 fe2b2de9 2020-01-15 rsc w->windowrect = r;
724 50923426 2020-01-13 rsc * Allocate our local backing store.
726 50923426 2020-01-13 rsc w->screenr = r;
727 50923426 2020-01-13 rsc w->screenpm = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth);
728 50923426 2020-01-13 rsc w->nextscreenpm = w->screenpm;
729 50923426 2020-01-13 rsc w->screenimage = _xallocmemimage(r, _x.chan, w->screenpm);
730 50923426 2020-01-13 rsc client->mouserect = r;
733 50923426 2020-01-13 rsc * Allocate some useful graphics contexts for the future.
734 50923426 2020-01-13 rsc * These can be used with any drawable matching w->drawable's
735 50923426 2020-01-13 rsc * pixel format (which is all the drawables we create).
737 50923426 2020-01-13 rsc if(_x.gcfill == 0) {
738 50923426 2020-01-13 rsc _x.gcfill = xgc(w->screenpm, FillSolid, -1);
739 50923426 2020-01-13 rsc _x.gccopy = xgc(w->screenpm, -1, -1);
740 50923426 2020-01-13 rsc _x.gcsimplesrc = xgc(w->screenpm, FillStippled, -1);
741 50923426 2020-01-13 rsc _x.gczero = xgc(w->screenpm, -1, -1);
742 50923426 2020-01-13 rsc _x.gcreplsrc = xgc(w->screenpm, FillTiled, -1);
744 50923426 2020-01-13 rsc pmid = XCreatePixmap(_x.display, w->drawable, 1, 1, 1);
745 50923426 2020-01-13 rsc _x.gcfill0 = xgc(pmid, FillSolid, 0);
746 50923426 2020-01-13 rsc _x.gccopy0 = xgc(pmid, -1, -1);
747 50923426 2020-01-13 rsc _x.gcsimplesrc0 = xgc(pmid, FillStippled, -1);
748 50923426 2020-01-13 rsc _x.gczero0 = xgc(pmid, -1, -1);
749 50923426 2020-01-13 rsc _x.gcreplsrc0 = xgc(pmid, FillTiled, -1);
750 50923426 2020-01-13 rsc XFreePixmap(_x.display, pmid);
753 50923426 2020-01-13 rsc return w->screenimage;
757 50923426 2020-01-13 rsc rpc_attach(Client *client, char *label, char *winsize)
759 50923426 2020-01-13 rsc Memimage *m;
762 50923426 2020-01-13 rsc m = xattach(client, label, winsize);
768 50923426 2020-01-13 rsc rpc_setlabel(Client *client, char *label)
770 50923426 2020-01-13 rsc Xwin *w = (Xwin*)client->view;
771 50923426 2020-01-13 rsc XTextProperty name;
774 50923426 2020-01-13 rsc * Label and other properties required by ICCCCM.
777 50923426 2020-01-13 rsc memset(&name, 0, sizeof name);
778 50923426 2020-01-13 rsc if(label == nil)
779 50923426 2020-01-13 rsc label = "pjw-face-here";
780 50923426 2020-01-13 rsc name.value = (uchar*)label;
781 50923426 2020-01-13 rsc name.encoding = XA_STRING;
782 50923426 2020-01-13 rsc name.format = 8;
783 50923426 2020-01-13 rsc name.nitems = strlen((char*)name.value);
785 50923426 2020-01-13 rsc XSetWMProperties(
786 50923426 2020-01-13 rsc _x.display, /* display */
787 50923426 2020-01-13 rsc w->drawable, /* window */
788 50923426 2020-01-13 rsc &name, /* XA_WM_NAME property */
789 50923426 2020-01-13 rsc &name, /* XA_WM_ICON_NAME property */
790 50923426 2020-01-13 rsc nil, /* XA_WM_COMMAND */
791 50923426 2020-01-13 rsc 0, /* argc */
792 50923426 2020-01-13 rsc nil, /* XA_WM_NORMAL_HINTS */
793 50923426 2020-01-13 rsc nil, /* XA_WM_HINTS */
794 50923426 2020-01-13 rsc nil /* XA_WM_CLASSHINTS */
796 50923426 2020-01-13 rsc XFlush(_x.display);
801 50923426 2020-01-13 rsc * Create a GC with a particular fill style and XXX.
802 50923426 2020-01-13 rsc * Disable generation of GraphicsExpose/NoExpose events in the GC.
805 50923426 2020-01-13 rsc xgc(XDrawable d, int fillstyle, int foreground)
808 50923426 2020-01-13 rsc XGCValues v;
810 50923426 2020-01-13 rsc memset(&v, 0, sizeof v);
811 50923426 2020-01-13 rsc v.function = GXcopy;
812 50923426 2020-01-13 rsc v.graphics_exposures = False;
813 50923426 2020-01-13 rsc gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v);
814 50923426 2020-01-13 rsc if(fillstyle != -1)
815 50923426 2020-01-13 rsc XSetFillStyle(_x.display, gc, fillstyle);
816 50923426 2020-01-13 rsc if(foreground != -1)
817 50923426 2020-01-13 rsc XSetForeground(_x.display, gc, 0);
823 50923426 2020-01-13 rsc * Initialize map with the Plan 9 rgbv color map.
826 50923426 2020-01-13 rsc plan9cmap(void)
828 50923426 2020-01-13 rsc int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
829 50923426 2020-01-13 rsc static int once;
835 50923426 2020-01-13 rsc for(r=0; r!=4; r++)
836 50923426 2020-01-13 rsc for(g = 0; g != 4; g++)
837 50923426 2020-01-13 rsc for(b = 0; b!=4; b++)
838 50923426 2020-01-13 rsc for(v = 0; v!=4; v++){
844 50923426 2020-01-13 rsc /* divide check -- pick grey shades */
846 50923426 2020-01-13 rsc cr=cg=cb=v*17;
848 50923426 2020-01-13 rsc num=17*(4*den+v);
849 50923426 2020-01-13 rsc cr=r*num/den;
850 50923426 2020-01-13 rsc cg=g*num/den;
851 50923426 2020-01-13 rsc cb=b*num/den;
853 50923426 2020-01-13 rsc idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
854 50923426 2020-01-13 rsc _x.map[idx].red = cr*0x0101;
855 50923426 2020-01-13 rsc _x.map[idx].green = cg*0x0101;
856 50923426 2020-01-13 rsc _x.map[idx].blue = cb*0x0101;
857 50923426 2020-01-13 rsc _x.map[idx].pixel = idx;
858 50923426 2020-01-13 rsc _x.map[idx].flags = DoRed|DoGreen|DoBlue;
860 50923426 2020-01-13 rsc v7 = v >> 1;
861 50923426 2020-01-13 rsc idx7 = r*32 + v7*16 + g*4 + b;
862 50923426 2020-01-13 rsc if((v & 1) == v7){
863 50923426 2020-01-13 rsc _x.map7to8[idx7][0] = idx;
864 50923426 2020-01-13 rsc if(den == 0) { /* divide check -- pick grey shades */
865 50923426 2020-01-13 rsc cr = ((255.0/7.0)*v7)+0.5;
870 50923426 2020-01-13 rsc num=17*15*(4*den+v7*2)/14;
871 50923426 2020-01-13 rsc cr=r*num/den;
872 50923426 2020-01-13 rsc cg=g*num/den;
873 50923426 2020-01-13 rsc cb=b*num/den;
875 50923426 2020-01-13 rsc _x.map7[idx7].red = cr*0x0101;
876 50923426 2020-01-13 rsc _x.map7[idx7].green = cg*0x0101;
877 50923426 2020-01-13 rsc _x.map7[idx7].blue = cb*0x0101;
878 50923426 2020-01-13 rsc _x.map7[idx7].pixel = idx7;
879 50923426 2020-01-13 rsc _x.map7[idx7].flags = DoRed|DoGreen|DoBlue;
882 50923426 2020-01-13 rsc _x.map7to8[idx7][1] = idx;
887 50923426 2020-01-13 rsc * Initialize and install the rgbv color map as a private color map
888 50923426 2020-01-13 rsc * for this application. It gets the best colors when it has the
889 50923426 2020-01-13 rsc * cursor focus.
891 50923426 2020-01-13 rsc * We always choose the best depth possible, but that might not
892 50923426 2020-01-13 rsc * be the default depth. On such "suboptimal" systems, we have to allocate an
893 50923426 2020-01-13 rsc * empty color map anyway, according to Axel Belinfante.
896 50923426 2020-01-13 rsc setupcmap(XWindow w)
898 50923426 2020-01-13 rsc char buf[30];
900 50923426 2020-01-13 rsc u32int p, pp;
903 50923426 2020-01-13 rsc if(_x.depth <= 1)
906 50923426 2020-01-13 rsc if(_x.depth >= 24) {
907 50923426 2020-01-13 rsc if(_x.usetable == 0)
908 50923426 2020-01-13 rsc _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
911 50923426 2020-01-13 rsc * The pixel value returned from XGetPixel needs to
912 50923426 2020-01-13 rsc * be converted to RGB so we can call rgb2cmap()
913 50923426 2020-01-13 rsc * to translate between 24 bit X and our color. Unfortunately,
914 50923426 2020-01-13 rsc * the return value appears to be display server endian
915 50923426 2020-01-13 rsc * dependant. Therefore, we run some heuristics to later
916 50923426 2020-01-13 rsc * determine how to mask the int value correctly.
917 50923426 2020-01-13 rsc * Yeah, I know we can look at _x.vis->byte_order but
918 50923426 2020-01-13 rsc * some displays say MSB even though they run on LSB.
919 50923426 2020-01-13 rsc * Besides, this is more anal.
921 50923426 2020-01-13 rsc c = _x.map[19]; /* known to have different R, G, B values */
922 50923426 2020-01-13 rsc if(!XAllocColor(_x.display, _x.cmap, &c)){
923 50923426 2020-01-13 rsc werrstr("XAllocColor: %r");
926 50923426 2020-01-13 rsc p = c.pixel;
927 50923426 2020-01-13 rsc pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
928 50923426 2020-01-13 rsc if(pp != _x.map[19].pixel) {
929 50923426 2020-01-13 rsc /* check if endian is other way */
930 50923426 2020-01-13 rsc pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
931 50923426 2020-01-13 rsc if(pp != _x.map[19].pixel){
932 50923426 2020-01-13 rsc werrstr("cannot detect X server byte order");
936 50923426 2020-01-13 rsc switch(_x.chan){
938 50923426 2020-01-13 rsc _x.chan = BGR24;
940 50923426 2020-01-13 rsc case XRGB32:
941 50923426 2020-01-13 rsc _x.chan = XBGR32;
944 50923426 2020-01-13 rsc werrstr("cannot byteswap channel %s",
945 50923426 2020-01-13 rsc chantostr(buf, _x.chan));
949 50923426 2020-01-13 rsc }else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){
951 50923426 2020-01-13 rsc * Do nothing. We have no way to express a
952 50923426 2020-01-13 rsc * mixed-endian 16-bit screen, so pretend they don't exist.
954 50923426 2020-01-13 rsc if(_x.usetable == 0)
955 50923426 2020-01-13 rsc _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
956 50923426 2020-01-13 rsc }else if(_x.vis->class == PseudoColor){
957 50923426 2020-01-13 rsc if(_x.usetable == 0){
958 50923426 2020-01-13 rsc _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll);
959 50923426 2020-01-13 rsc XStoreColors(_x.display, _x.cmap, _x.map, 256);
960 50923426 2020-01-13 rsc for(i = 0; i < 256; i++){
961 50923426 2020-01-13 rsc _x.tox11[i] = i;
962 50923426 2020-01-13 rsc _x.toplan9[i] = i;
965 50923426 2020-01-13 rsc for(i = 0; i < 128; i++){
966 50923426 2020-01-13 rsc c = _x.map7[i];
967 50923426 2020-01-13 rsc if(!XAllocColor(_x.display, _x.cmap, &c)){
968 50923426 2020-01-13 rsc werrstr("can't allocate colors in 7-bit map");
971 50923426 2020-01-13 rsc _x.tox11[_x.map7to8[i][0]] = c.pixel;
972 50923426 2020-01-13 rsc _x.tox11[_x.map7to8[i][1]] = c.pixel;
973 50923426 2020-01-13 rsc _x.toplan9[c.pixel] = _x.map7to8[i][0];
977 50923426 2020-01-13 rsc werrstr("unsupported visual class %d", _x.vis->class);
984 50923426 2020-01-13 rsc rpc_shutdown(void)
989 50923426 2020-01-13 rsc rpc_flush(Client *client, Rectangle r)
991 50923426 2020-01-13 rsc Xwin *w = (Xwin*)client->view;
994 50923426 2020-01-13 rsc if(w->nextscreenpm != w->screenpm){
995 50923426 2020-01-13 rsc XSync(_x.display, False);
996 50923426 2020-01-13 rsc XFreePixmap(_x.display, w->screenpm);
997 50923426 2020-01-13 rsc w->screenpm = w->nextscreenpm;
1000 50923426 2020-01-13 rsc if(r.min.x >= r.max.x || r.min.y >= r.max.y) {
1005 50923426 2020-01-13 rsc XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
1006 50923426 2020-01-13 rsc Dx(r), Dy(r), r.min.x, r.min.y);
1007 50923426 2020-01-13 rsc XFlush(_x.display);
1011 50923426 2020-01-13 rsc static void
1012 50923426 2020-01-13 rsc _xexpose(Xwin *w, XEvent *e)
1014 50923426 2020-01-13 rsc XExposeEvent *xe;
1015 50923426 2020-01-13 rsc Rectangle r;
1017 50923426 2020-01-13 rsc if(w->screenpm != w->nextscreenpm)
1019 50923426 2020-01-13 rsc xe = (XExposeEvent*)e;
1020 50923426 2020-01-13 rsc r.min.x = xe->x;
1021 50923426 2020-01-13 rsc r.min.y = xe->y;
1022 50923426 2020-01-13 rsc r.max.x = xe->x+xe->width;
1023 50923426 2020-01-13 rsc r.max.y = xe->y+xe->height;
1024 50923426 2020-01-13 rsc XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
1025 50923426 2020-01-13 rsc Dx(r), Dy(r), r.min.x, r.min.y);
1026 50923426 2020-01-13 rsc XSync(_x.display, False);
1030 50923426 2020-01-13 rsc _xdestroy(Xwin *w, XEvent *e)
1032 50923426 2020-01-13 rsc XDestroyWindowEvent *xe;
1034 50923426 2020-01-13 rsc xe = (XDestroyWindowEvent*)e;
1035 50923426 2020-01-13 rsc if(xe->window == w->drawable){
1036 50923426 2020-01-13 rsc w->destroyed = 1;
1043 50923426 2020-01-13 rsc _xconfigure(Xwin *w, XEvent *e)
1045 50923426 2020-01-13 rsc Rectangle r;
1046 50923426 2020-01-13 rsc XConfigureEvent *xe = (XConfigureEvent*)e;
1048 50923426 2020-01-13 rsc if(!w->fullscreen){
1049 50923426 2020-01-13 rsc int rx, ry;
1050 50923426 2020-01-13 rsc XWindow xw;
1051 50923426 2020-01-13 rsc if(XTranslateCoordinates(_x.display, w->drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &xw))
1052 50923426 2020-01-13 rsc w->windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height);
1055 50923426 2020-01-13 rsc if(xe->width == Dx(w->screenr) && xe->height == Dy(w->screenr))
1057 50923426 2020-01-13 rsc r = Rect(0, 0, xe->width, xe->height);
1059 50923426 2020-01-13 rsc if(w->screenpm != w->nextscreenpm){
1060 50923426 2020-01-13 rsc XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
1061 50923426 2020-01-13 rsc Dx(r), Dy(r), r.min.x, r.min.y);
1062 50923426 2020-01-13 rsc XSync(_x.display, False);
1064 50923426 2020-01-13 rsc w->newscreenr = r;
1069 50923426 2020-01-13 rsc _xreplacescreenimage(Client *client)
1071 50923426 2020-01-13 rsc Memimage *m;
1072 50923426 2020-01-13 rsc XDrawable pixmap;
1073 50923426 2020-01-13 rsc Rectangle r;
1076 50923426 2020-01-13 rsc w = (Xwin*)client->view;
1077 50923426 2020-01-13 rsc r = w->newscreenr;
1078 50923426 2020-01-13 rsc pixmap = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth);
1079 50923426 2020-01-13 rsc m = _xallocmemimage(r, _x.chan, pixmap);
1080 50923426 2020-01-13 rsc if(w->nextscreenpm != w->screenpm)
1081 50923426 2020-01-13 rsc XFreePixmap(_x.display, w->nextscreenpm);
1082 50923426 2020-01-13 rsc w->nextscreenpm = pixmap;
1083 50923426 2020-01-13 rsc w->screenr = r;
1084 50923426 2020-01-13 rsc client->mouserect = r;
1086 50923426 2020-01-13 rsc gfx_replacescreenimage(client, m);
1092 50923426 2020-01-13 rsc rpc_resizeimg(Client *client)
1095 50923426 2020-01-13 rsc _xreplacescreenimage(client);
1100 50923426 2020-01-13 rsc rpc_gfxdrawlock(void)
1106 50923426 2020-01-13 rsc rpc_gfxdrawunlock(void)
1111 50923426 2020-01-13 rsc rpc_topwin(Client *client)
1113 50923426 2020-01-13 rsc Xwin *w = (Xwin*)client->view;
1116 50923426 2020-01-13 rsc XMapRaised(_x.display, w->drawable);
1117 50923426 2020-01-13 rsc XSetInputFocus(_x.display, w->drawable, RevertToPointerRoot,
1118 50923426 2020-01-13 rsc CurrentTime);
1119 50923426 2020-01-13 rsc XFlush(_x.display);
1124 50923426 2020-01-13 rsc rpc_resizewindow(Client *client, Rectangle r)
1126 50923426 2020-01-13 rsc Xwin *w = (Xwin*)client->view;
1127 50923426 2020-01-13 rsc XWindowChanges e;
1128 50923426 2020-01-13 rsc int value_mask;
1131 50923426 2020-01-13 rsc memset(&e, 0, sizeof e);
1132 50923426 2020-01-13 rsc value_mask = CWX|CWY|CWWidth|CWHeight;
1133 50923426 2020-01-13 rsc e.width = Dx(r);
1134 50923426 2020-01-13 rsc e.height = Dy(r);
1135 50923426 2020-01-13 rsc XConfigureWindow(_x.display, w->drawable, value_mask, &e);
1136 50923426 2020-01-13 rsc XFlush(_x.display);
1140 50923426 2020-01-13 rsc static void
1141 50923426 2020-01-13 rsc _xmovewindow(Xwin *w, Rectangle r)
1143 50923426 2020-01-13 rsc XWindowChanges e;
1144 50923426 2020-01-13 rsc int value_mask;
1146 50923426 2020-01-13 rsc memset(&e, 0, sizeof e);
1147 50923426 2020-01-13 rsc value_mask = CWX|CWY|CWWidth|CWHeight;
1148 50923426 2020-01-13 rsc e.x = r.min.x;
1149 50923426 2020-01-13 rsc e.y = r.min.y;
1150 50923426 2020-01-13 rsc e.width = Dx(r);
1151 50923426 2020-01-13 rsc e.height = Dy(r);
1152 50923426 2020-01-13 rsc XConfigureWindow(_x.display, w->drawable, value_mask, &e);
1153 50923426 2020-01-13 rsc XFlush(_x.display);
1157 50923426 2020-01-13 rsc _xtoplan9kbd(XEvent *e)
1161 50923426 2020-01-13 rsc if(e->xany.type != KeyPress)
1163 50923426 2020-01-13 rsc needstack(64*1024); /* X has some *huge* buffers in openobject */
1164 50923426 2020-01-13 rsc /* and they're even bigger on SuSE */
1165 50923426 2020-01-13 rsc XLookupString((XKeyEvent*)e,NULL,0,&k,NULL);
1166 50923426 2020-01-13 rsc if(k == NoSymbol)
1169 50923426 2020-01-13 rsc if(k&0xFF00){
1171 50923426 2020-01-13 rsc case XK_BackSpace:
1172 50923426 2020-01-13 rsc case XK_Tab:
1173 50923426 2020-01-13 rsc case XK_Escape:
1174 50923426 2020-01-13 rsc case XK_Delete:
1175 50923426 2020-01-13 rsc case XK_KP_0:
1176 50923426 2020-01-13 rsc case XK_KP_1:
1177 50923426 2020-01-13 rsc case XK_KP_2:
1178 50923426 2020-01-13 rsc case XK_KP_3:
1179 50923426 2020-01-13 rsc case XK_KP_4:
1180 50923426 2020-01-13 rsc case XK_KP_5:
1181 50923426 2020-01-13 rsc case XK_KP_6:
1182 50923426 2020-01-13 rsc case XK_KP_7:
1183 50923426 2020-01-13 rsc case XK_KP_8:
1184 50923426 2020-01-13 rsc case XK_KP_9:
1185 50923426 2020-01-13 rsc case XK_KP_Divide:
1186 50923426 2020-01-13 rsc case XK_KP_Multiply:
1187 50923426 2020-01-13 rsc case XK_KP_Subtract:
1188 50923426 2020-01-13 rsc case XK_KP_Add:
1189 50923426 2020-01-13 rsc case XK_KP_Decimal:
1192 50923426 2020-01-13 rsc case XK_Linefeed:
1195 50923426 2020-01-13 rsc case XK_KP_Space:
1198 50923426 2020-01-13 rsc case XK_Home:
1199 50923426 2020-01-13 rsc case XK_KP_Home:
1202 50923426 2020-01-13 rsc case XK_Left:
1203 50923426 2020-01-13 rsc case XK_KP_Left:
1206 50923426 2020-01-13 rsc case XK_Up:
1207 50923426 2020-01-13 rsc case XK_KP_Up:
1210 50923426 2020-01-13 rsc case XK_Down:
1211 50923426 2020-01-13 rsc case XK_KP_Down:
1214 50923426 2020-01-13 rsc case XK_Right:
1215 50923426 2020-01-13 rsc case XK_KP_Right:
1216 50923426 2020-01-13 rsc k = Kright;
1218 50923426 2020-01-13 rsc case XK_Page_Down:
1219 50923426 2020-01-13 rsc case XK_KP_Page_Down:
1220 50923426 2020-01-13 rsc k = Kpgdown;
1222 50923426 2020-01-13 rsc case XK_End:
1223 50923426 2020-01-13 rsc case XK_KP_End:
1226 50923426 2020-01-13 rsc case XK_Page_Up:
1227 50923426 2020-01-13 rsc case XK_KP_Page_Up:
1230 50923426 2020-01-13 rsc case XK_Insert:
1231 50923426 2020-01-13 rsc case XK_KP_Insert:
1234 50923426 2020-01-13 rsc case XK_KP_Enter:
1235 50923426 2020-01-13 rsc case XK_Return:
1238 50923426 2020-01-13 rsc case XK_Alt_L:
1239 50923426 2020-01-13 rsc case XK_Meta_L: /* Shift Alt on PCs */
1240 50923426 2020-01-13 rsc case XK_Alt_R:
1241 50923426 2020-01-13 rsc case XK_Meta_R: /* Shift Alt on PCs */
1242 50923426 2020-01-13 rsc case XK_Multi_key:
1244 50923426 2020-01-13 rsc default: /* not ISO-1 or tty control */
1245 50923426 2020-01-13 rsc if(k>0xff) {
1246 50923426 2020-01-13 rsc k = _p9keysym2ucs(k);
1247 50923426 2020-01-13 rsc if(k==-1) return -1;
1252 50923426 2020-01-13 rsc /* Compensate for servers that call a minus a hyphen */
1253 50923426 2020-01-13 rsc if(k == XK_hyphen)
1254 50923426 2020-01-13 rsc k = XK_minus;
1255 50923426 2020-01-13 rsc /* Do control mapping ourselves if translator doesn't */
1256 50923426 2020-01-13 rsc if(e->xkey.state&ControlMask)
1258 50923426 2020-01-13 rsc if(k == NoSymbol) {
1262 50923426 2020-01-13 rsc return k+0;
1266 50923426 2020-01-13 rsc _xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m)
1269 50923426 2020-01-13 rsc XButtonEvent *be;
1270 50923426 2020-01-13 rsc XMotionEvent *me;
1272 50923426 2020-01-13 rsc if(_x.putsnarf != _x.assertsnarf){
1273 50923426 2020-01-13 rsc _x.assertsnarf = _x.putsnarf;
1274 50923426 2020-01-13 rsc XSetSelectionOwner(_x.display, XA_PRIMARY, w->drawable, CurrentTime);
1275 50923426 2020-01-13 rsc if(_x.clipboard != None)
1276 50923426 2020-01-13 rsc XSetSelectionOwner(_x.display, _x.clipboard, w->drawable, CurrentTime);
1277 50923426 2020-01-13 rsc XFlush(_x.display);
1280 50923426 2020-01-13 rsc switch(e->type){
1281 50923426 2020-01-13 rsc case ButtonPress:
1282 50923426 2020-01-13 rsc be = (XButtonEvent*)e;
1285 50923426 2020-01-13 rsc * Fake message, just sent to make us announce snarf.
1286 50923426 2020-01-13 rsc * Apparently state and button are 16 and 8 bits on
1287 50923426 2020-01-13 rsc * the wire, since they are truncated by the time they
1288 50923426 2020-01-13 rsc * get to us.
1290 50923426 2020-01-13 rsc if(be->send_event
1291 50923426 2020-01-13 rsc && (~be->state&0xFFFF)==0
1292 50923426 2020-01-13 rsc && (~be->button&0xFF)==0)
1294 50923426 2020-01-13 rsc /* BUG? on mac need to inherit these from elsewhere? */
1295 50923426 2020-01-13 rsc m->xy.x = be->x;
1296 50923426 2020-01-13 rsc m->xy.y = be->y;
1297 50923426 2020-01-13 rsc s = be->state;
1298 50923426 2020-01-13 rsc m->msec = be->time;
1299 50923426 2020-01-13 rsc switch(be->button){
1301 50923426 2020-01-13 rsc s |= Button1Mask;
1304 50923426 2020-01-13 rsc s |= Button2Mask;
1307 50923426 2020-01-13 rsc s |= Button3Mask;
1310 50923426 2020-01-13 rsc s |= Button4Mask;
1313 50923426 2020-01-13 rsc s |= Button5Mask;
1317 50923426 2020-01-13 rsc case ButtonRelease:
1318 50923426 2020-01-13 rsc be = (XButtonEvent*)e;
1319 50923426 2020-01-13 rsc m->xy.x = be->x;
1320 50923426 2020-01-13 rsc m->xy.y = be->y;
1321 50923426 2020-01-13 rsc s = be->state;
1322 50923426 2020-01-13 rsc m->msec = be->time;
1323 50923426 2020-01-13 rsc switch(be->button){
1325 50923426 2020-01-13 rsc s &= ~Button1Mask;
1328 50923426 2020-01-13 rsc s &= ~Button2Mask;
1331 50923426 2020-01-13 rsc s &= ~Button3Mask;
1334 50923426 2020-01-13 rsc s &= ~Button4Mask;
1337 50923426 2020-01-13 rsc s &= ~Button5Mask;
1342 50923426 2020-01-13 rsc case MotionNotify:
1343 50923426 2020-01-13 rsc me = (XMotionEvent*)e;
1344 50923426 2020-01-13 rsc s = me->state;
1345 50923426 2020-01-13 rsc m->xy.x = me->x;
1346 50923426 2020-01-13 rsc m->xy.y = me->y;
1347 50923426 2020-01-13 rsc m->msec = me->time;
1348 50923426 2020-01-13 rsc return 0; // do not set buttons
1354 50923426 2020-01-13 rsc m->buttons = 0;
1355 50923426 2020-01-13 rsc if(s & Button1Mask)
1356 50923426 2020-01-13 rsc m->buttons |= 1;
1357 50923426 2020-01-13 rsc if(s & Button2Mask)
1358 50923426 2020-01-13 rsc m->buttons |= 2;
1359 50923426 2020-01-13 rsc if(s & Button3Mask)
1360 50923426 2020-01-13 rsc m->buttons |= 4;
1361 50923426 2020-01-13 rsc if(s & Button4Mask)
1362 50923426 2020-01-13 rsc m->buttons |= 8;
1363 50923426 2020-01-13 rsc if(s & Button5Mask)
1364 50923426 2020-01-13 rsc m->buttons |= 16;
1369 50923426 2020-01-13 rsc rpc_setmouse(Client *client, Point p)
1371 50923426 2020-01-13 rsc Xwin *w = (Xwin*)client->view;
1374 50923426 2020-01-13 rsc XWarpPointer(_x.display, None, w->drawable, 0, 0, 0, 0, p.x, p.y);
1375 50923426 2020-01-13 rsc XFlush(_x.display);
1380 50923426 2020-01-13 rsc revbyte(int b)
1385 50923426 2020-01-13 rsc r |= (b&0x01) << 7;
1386 50923426 2020-01-13 rsc r |= (b&0x02) << 5;
1387 50923426 2020-01-13 rsc r |= (b&0x04) << 3;
1388 50923426 2020-01-13 rsc r |= (b&0x08) << 1;
1389 50923426 2020-01-13 rsc r |= (b&0x10) >> 1;
1390 50923426 2020-01-13 rsc r |= (b&0x20) >> 3;
1391 50923426 2020-01-13 rsc r |= (b&0x40) >> 5;
1392 50923426 2020-01-13 rsc r |= (b&0x80) >> 7;
1396 50923426 2020-01-13 rsc static void
1397 50923426 2020-01-13 rsc xcursorarrow(Xwin *w)
1399 50923426 2020-01-13 rsc if(_x.cursor != 0){
1400 50923426 2020-01-13 rsc XFreeCursor(_x.display, _x.cursor);
1401 50923426 2020-01-13 rsc _x.cursor = 0;
1403 50923426 2020-01-13 rsc XUndefineCursor(_x.display, w->drawable);
1404 50923426 2020-01-13 rsc XFlush(_x.display);
1409 50923426 2020-01-13 rsc rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
1411 50923426 2020-01-13 rsc Xwin *w = (Xwin*)client->view;
1412 50923426 2020-01-13 rsc XColor fg, bg;
1413 50923426 2020-01-13 rsc XCursor xc;
1414 50923426 2020-01-13 rsc Pixmap xsrc, xmask;
1416 50923426 2020-01-13 rsc uchar src[2*16], mask[2*16];
1421 50923426 2020-01-13 rsc if(c == nil){
1422 50923426 2020-01-13 rsc xcursorarrow(w);
1426 50923426 2020-01-13 rsc for(i=0; i<2*16; i++){
1427 50923426 2020-01-13 rsc src[i] = revbyte(c->set[i]);
1428 50923426 2020-01-13 rsc mask[i] = revbyte(c->set[i] | c->clr[i]);
1431 50923426 2020-01-13 rsc fg = _x.map[0];
1432 50923426 2020-01-13 rsc bg = _x.map[255];
1433 50923426 2020-01-13 rsc xsrc = XCreateBitmapFromData(_x.display, w->drawable, (char*)src, 16, 16);
1434 50923426 2020-01-13 rsc xmask = XCreateBitmapFromData(_x.display, w->drawable, (char*)mask, 16, 16);
1435 50923426 2020-01-13 rsc xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y);
1436 50923426 2020-01-13 rsc if(xc != 0) {
1437 50923426 2020-01-13 rsc XDefineCursor(_x.display, w->drawable, xc);
1438 50923426 2020-01-13 rsc if(_x.cursor != 0)
1439 50923426 2020-01-13 rsc XFreeCursor(_x.display, _x.cursor);
1440 50923426 2020-01-13 rsc _x.cursor = xc;
1442 50923426 2020-01-13 rsc XFreePixmap(_x.display, xsrc);
1443 50923426 2020-01-13 rsc XFreePixmap(_x.display, xmask);
1444 50923426 2020-01-13 rsc XFlush(_x.display);
1450 50923426 2020-01-13 rsc char buf[SnarfSize];
1451 50923426 2020-01-13 rsc #ifdef APPLESNARF
1452 50923426 2020-01-13 rsc Rune rbuf[SnarfSize];
1453 50923426 2020-01-13 rsc PasteboardRef apple;
1457 50923426 2020-01-13 rsc static uchar*
1458 50923426 2020-01-13 rsc _xgetsnarffrom(Xwin *w, XWindow xw, Atom clipboard, Atom target, int timeout0, int timeout)
1460 50923426 2020-01-13 rsc Atom prop, type;
1461 50923426 2020-01-13 rsc ulong len, lastlen, dummy;
1462 50923426 2020-01-13 rsc int fmt, i;
1463 50923426 2020-01-13 rsc uchar *data, *xdata;
1466 50923426 2020-01-13 rsc * We should be waiting for SelectionNotify here, but it might never
1467 50923426 2020-01-13 rsc * come, and we have no way to time out. Instead, we will clear
1468 50923426 2020-01-13 rsc * local property #1, request our buddy to fill it in for us, and poll
1469 50923426 2020-01-13 rsc * until he's done or we get tired of waiting.
1472 50923426 2020-01-13 rsc XChangeProperty(_x.display, w->drawable, prop, target, 8, PropModeReplace, (uchar*)"", 0);
1473 50923426 2020-01-13 rsc XConvertSelection(_x.display, clipboard, target, prop, w->drawable, CurrentTime);
1474 50923426 2020-01-13 rsc XFlush(_x.display);
1475 50923426 2020-01-13 rsc lastlen = 0;
1476 50923426 2020-01-13 rsc timeout0 = (timeout0 + 9)/10;
1477 50923426 2020-01-13 rsc timeout = (timeout + 9)/10;
1478 50923426 2020-01-13 rsc for(i=0; i<timeout0 || (lastlen!=0 && i<timeout); i++){
1479 50923426 2020-01-13 rsc usleep(10*1000);
1480 50923426 2020-01-13 rsc XGetWindowProperty(_x.display, w->drawable, prop, 0, 0, 0, AnyPropertyType,
1481 50923426 2020-01-13 rsc &type, &fmt, &dummy, &len, &xdata);
1482 50923426 2020-01-13 rsc if(lastlen == len && len > 0){
1483 50923426 2020-01-13 rsc XFree(xdata);
1486 50923426 2020-01-13 rsc lastlen = len;
1487 50923426 2020-01-13 rsc XFree(xdata);
1489 50923426 2020-01-13 rsc if(len == 0)
1490 50923426 2020-01-13 rsc return nil;
1492 50923426 2020-01-13 rsc /* get the property */
1493 50923426 2020-01-13 rsc xdata = nil;
1494 50923426 2020-01-13 rsc XGetWindowProperty(_x.display, w->drawable, prop, 0, SnarfSize/sizeof(ulong), 0,
1495 50923426 2020-01-13 rsc AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
1496 50923426 2020-01-13 rsc if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){
1498 50923426 2020-01-13 rsc XFree(xdata);
1499 50923426 2020-01-13 rsc return nil;
1502 50923426 2020-01-13 rsc data = (uchar*)strdup((char*)xdata);
1503 50923426 2020-01-13 rsc XFree(xdata);
1504 50923426 2020-01-13 rsc return data;
1506 50923426 2020-01-13 rsc return nil;
1510 50923426 2020-01-13 rsc rpc_getsnarf(void)
1512 50923426 2020-01-13 rsc uchar *data;
1513 50923426 2020-01-13 rsc Atom clipboard;
1514 50923426 2020-01-13 rsc XWindow xw;
1517 50923426 2020-01-13 rsc qlock(&clip.lk);
1519 50923426 2020-01-13 rsc w = _x.windows;
1521 50923426 2020-01-13 rsc * Have we snarfed recently and the X server hasn't caught up?
1523 50923426 2020-01-13 rsc if(_x.putsnarf != _x.assertsnarf)
1527 50923426 2020-01-13 rsc * Is there a primary selection (highlighted text in an xterm)?
1529 50923426 2020-01-13 rsc clipboard = XA_PRIMARY;
1530 50923426 2020-01-13 rsc xw = XGetSelectionOwner(_x.display, XA_PRIMARY);
1531 50923426 2020-01-13 rsc // TODO check more
1532 50923426 2020-01-13 rsc if(xw == w->drawable){
1534 50923426 2020-01-13 rsc data = (uchar*)strdup(clip.buf);
1539 50923426 2020-01-13 rsc * If not, is there a clipboard selection?
1541 50923426 2020-01-13 rsc if(xw == None && _x.clipboard != None){
1542 50923426 2020-01-13 rsc clipboard = _x.clipboard;
1543 50923426 2020-01-13 rsc xw = XGetSelectionOwner(_x.display, _x.clipboard);
1544 50923426 2020-01-13 rsc if(xw == w->drawable)
1549 50923426 2020-01-13 rsc * If not, give up.
1551 50923426 2020-01-13 rsc if(xw == None){
1552 50923426 2020-01-13 rsc data = nil;
1556 50923426 2020-01-13 rsc if((data = _xgetsnarffrom(w, xw, clipboard, _x.utf8string, 10, 100)) == nil)
1557 50923426 2020-01-13 rsc if((data = _xgetsnarffrom(w, xw, clipboard, XA_STRING, 10, 100)) == nil){
1558 50923426 2020-01-13 rsc /* nothing left to do */
1563 50923426 2020-01-13 rsc qunlock(&clip.lk);
1564 50923426 2020-01-13 rsc return (char*)data;
1568 50923426 2020-01-13 rsc __xputsnarf(char *data)
1570 50923426 2020-01-13 rsc XButtonEvent e;
1573 50923426 2020-01-13 rsc if(strlen(data) >= SnarfSize)
1575 50923426 2020-01-13 rsc qlock(&clip.lk);
1577 50923426 2020-01-13 rsc w = _x.windows;
1578 50923426 2020-01-13 rsc strcpy(clip.buf, data);
1579 50923426 2020-01-13 rsc /* leave note for mouse proc to assert selection ownership */
1580 50923426 2020-01-13 rsc _x.putsnarf++;
1582 50923426 2020-01-13 rsc /* send mouse a fake event so snarf is announced */
1583 50923426 2020-01-13 rsc memset(&e, 0, sizeof e);
1584 50923426 2020-01-13 rsc e.type = ButtonPress;
1585 50923426 2020-01-13 rsc e.window = w->drawable;
1586 50923426 2020-01-13 rsc e.state = ~0;
1587 50923426 2020-01-13 rsc e.button = ~0;
1588 50923426 2020-01-13 rsc XSendEvent(_x.display, w->drawable, True, ButtonPressMask, (XEvent*)&e);
1589 50923426 2020-01-13 rsc XFlush(_x.display);
1591 50923426 2020-01-13 rsc qunlock(&clip.lk);
1595 50923426 2020-01-13 rsc _xselect(XEvent *e)
1597 50923426 2020-01-13 rsc char *name;
1599 50923426 2020-01-13 rsc XSelectionRequestEvent *xe;
1602 50923426 2020-01-13 rsc memset(&r, 0, sizeof r);
1603 50923426 2020-01-13 rsc xe = (XSelectionRequestEvent*)e;
1604 50923426 2020-01-13 rsc if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d (sizeof atom=%d)\n",
1605 50923426 2020-01-13 rsc xe->target, xe->requestor, xe->property, xe->selection, sizeof a[0]);
1606 50923426 2020-01-13 rsc r.xselection.property = xe->property;
1607 50923426 2020-01-13 rsc if(xe->target == _x.targets){
1608 50923426 2020-01-13 rsc a[0] = _x.utf8string;
1609 50923426 2020-01-13 rsc a[1] = XA_STRING;
1610 50923426 2020-01-13 rsc a[2] = _x.text;
1611 50923426 2020-01-13 rsc a[3] = _x.compoundtext;
1612 50923426 2020-01-13 rsc XChangeProperty(_x.display, xe->requestor, xe->property, XA_ATOM,
1613 50923426 2020-01-13 rsc 32, PropModeReplace, (uchar*)a, nelem(a));
1614 50923426 2020-01-13 rsc }else if(xe->target == XA_STRING
1615 50923426 2020-01-13 rsc || xe->target == _x.utf8string
1616 50923426 2020-01-13 rsc || xe->target == _x.text
1617 50923426 2020-01-13 rsc || xe->target == _x.compoundtext
1618 50923426 2020-01-13 rsc || ((name = XGetAtomName(_x.display, xe->target)) && strcmp(name, "text/plain;charset=UTF-8") == 0)){
1619 50923426 2020-01-13 rsc /* text/plain;charset=UTF-8 seems nonstandard but is used by Synergy */
1620 50923426 2020-01-13 rsc /* if the target is STRING we're supposed to reply with Latin1 XXX */
1621 50923426 2020-01-13 rsc qlock(&clip.lk);
1622 50923426 2020-01-13 rsc XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
1623 50923426 2020-01-13 rsc 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
1624 50923426 2020-01-13 rsc qunlock(&clip.lk);
1626 50923426 2020-01-13 rsc if(strcmp(name, "TIMESTAMP") != 0)
1627 50923426 2020-01-13 rsc fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
1628 50923426 2020-01-13 rsc r.xselection.property = None;
1631 50923426 2020-01-13 rsc r.xselection.display = xe->display;
1632 50923426 2020-01-13 rsc /* r.xselection.property filled above */
1633 50923426 2020-01-13 rsc r.xselection.target = xe->target;
1634 50923426 2020-01-13 rsc r.xselection.type = SelectionNotify;
1635 50923426 2020-01-13 rsc r.xselection.requestor = xe->requestor;
1636 50923426 2020-01-13 rsc r.xselection.time = xe->time;
1637 50923426 2020-01-13 rsc r.xselection.send_event = True;
1638 50923426 2020-01-13 rsc r.xselection.selection = xe->selection;
1639 50923426 2020-01-13 rsc XSendEvent(_x.display, xe->requestor, False, 0, &r);
1640 50923426 2020-01-13 rsc XFlush(_x.display);
1644 50923426 2020-01-13 rsc #ifdef APPLESNARF
1646 50923426 2020-01-13 rsc _applegetsnarf(void)
1648 50923426 2020-01-13 rsc char *s, *t;
1649 50923426 2020-01-13 rsc CFArrayRef flavors;
1650 50923426 2020-01-13 rsc CFDataRef data;
1651 50923426 2020-01-13 rsc CFIndex nflavor, ndata, j;
1652 50923426 2020-01-13 rsc CFStringRef type;
1653 50923426 2020-01-13 rsc ItemCount nitem;
1654 50923426 2020-01-13 rsc PasteboardItemID id;
1655 50923426 2020-01-13 rsc PasteboardSyncFlags flags;
1658 50923426 2020-01-13 rsc /* fprint(2, "applegetsnarf\n"); */
1659 50923426 2020-01-13 rsc qlock(&clip.lk);
1660 50923426 2020-01-13 rsc if(clip.apple == nil){
1661 50923426 2020-01-13 rsc if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
1662 50923426 2020-01-13 rsc fprint(2, "apple pasteboard create failed\n");
1663 50923426 2020-01-13 rsc qunlock(&clip.lk);
1664 50923426 2020-01-13 rsc return nil;
1667 50923426 2020-01-13 rsc flags = PasteboardSynchronize(clip.apple);
1668 50923426 2020-01-13 rsc if(flags&kPasteboardClientIsOwner){
1669 50923426 2020-01-13 rsc s = strdup(clip.buf);
1670 50923426 2020-01-13 rsc qunlock(&clip.lk);
1673 50923426 2020-01-13 rsc if(PasteboardGetItemCount(clip.apple, &nitem) != noErr){
1674 50923426 2020-01-13 rsc fprint(2, "apple pasteboard get item count failed\n");
1675 50923426 2020-01-13 rsc qunlock(&clip.lk);
1676 50923426 2020-01-13 rsc return nil;
1678 50923426 2020-01-13 rsc for(i=1; i<=nitem; i++){
1679 50923426 2020-01-13 rsc if(PasteboardGetItemIdentifier(clip.apple, i, &id) != noErr)
1681 50923426 2020-01-13 rsc if(PasteboardCopyItemFlavors(clip.apple, id, &flavors) != noErr)
1683 50923426 2020-01-13 rsc nflavor = CFArrayGetCount(flavors);
1684 50923426 2020-01-13 rsc for(j=0; j<nflavor; j++){
1685 50923426 2020-01-13 rsc type = (CFStringRef)CFArrayGetValueAtIndex(flavors, j);
1686 50923426 2020-01-13 rsc if(!UTTypeConformsTo(type, CFSTR("public.utf16-plain-text")))
1688 50923426 2020-01-13 rsc if(PasteboardCopyItemFlavorData(clip.apple, id, type, &data) != noErr)
1690 50923426 2020-01-13 rsc ndata = CFDataGetLength(data);
1691 50923426 2020-01-13 rsc qunlock(&clip.lk);
1692 50923426 2020-01-13 rsc s = smprint("%.*S", ndata/2, (Rune*)CFDataGetBytePtr(data));
1693 50923426 2020-01-13 rsc CFRelease(flavors);
1694 50923426 2020-01-13 rsc CFRelease(data);
1695 50923426 2020-01-13 rsc for(t=s; *t; t++)
1696 50923426 2020-01-13 rsc if(*t == '\r')
1700 50923426 2020-01-13 rsc CFRelease(flavors);
1702 50923426 2020-01-13 rsc qunlock(&clip.lk);
1703 50923426 2020-01-13 rsc return nil;
1707 50923426 2020-01-13 rsc _appleputsnarf(char *s)
1709 50923426 2020-01-13 rsc CFDataRef cfdata;
1710 50923426 2020-01-13 rsc PasteboardSyncFlags flags;
1712 50923426 2020-01-13 rsc /* fprint(2, "appleputsnarf\n"); */
1714 50923426 2020-01-13 rsc if(strlen(s) >= SnarfSize)
1716 50923426 2020-01-13 rsc qlock(&clip.lk);
1717 50923426 2020-01-13 rsc strcpy(clip.buf, s);
1718 50923426 2020-01-13 rsc runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s);
1719 50923426 2020-01-13 rsc if(clip.apple == nil){
1720 50923426 2020-01-13 rsc if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
1721 50923426 2020-01-13 rsc fprint(2, "apple pasteboard create failed\n");
1722 50923426 2020-01-13 rsc qunlock(&clip.lk);
1726 50923426 2020-01-13 rsc if(PasteboardClear(clip.apple) != noErr){
1727 50923426 2020-01-13 rsc fprint(2, "apple pasteboard clear failed\n");
1728 50923426 2020-01-13 rsc qunlock(&clip.lk);
1731 50923426 2020-01-13 rsc flags = PasteboardSynchronize(clip.apple);
1732 50923426 2020-01-13 rsc if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
1733 50923426 2020-01-13 rsc fprint(2, "apple pasteboard cannot assert ownership\n");
1734 50923426 2020-01-13 rsc qunlock(&clip.lk);
1737 50923426 2020-01-13 rsc cfdata = CFDataCreate(kCFAllocatorDefault,
1738 50923426 2020-01-13 rsc (uchar*)clip.rbuf, runestrlen(clip.rbuf)*2);
1739 50923426 2020-01-13 rsc if(cfdata == nil){
1740 50923426 2020-01-13 rsc fprint(2, "apple pasteboard cfdatacreate failed\n");
1741 50923426 2020-01-13 rsc qunlock(&clip.lk);
1744 50923426 2020-01-13 rsc if(PasteboardPutItemFlavor(clip.apple, (PasteboardItemID)1,
1745 50923426 2020-01-13 rsc CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){
1746 50923426 2020-01-13 rsc fprint(2, "apple pasteboard putitem failed\n");
1747 50923426 2020-01-13 rsc CFRelease(cfdata);
1748 50923426 2020-01-13 rsc qunlock(&clip.lk);
1751 50923426 2020-01-13 rsc /* CFRelease(cfdata); ??? */
1752 50923426 2020-01-13 rsc qunlock(&clip.lk);
1754 50923426 2020-01-13 rsc #endif /* APPLESNARF */
1757 50923426 2020-01-13 rsc rpc_putsnarf(char *data)
1759 50923426 2020-01-13 rsc #ifdef APPLESNARF
1760 50923426 2020-01-13 rsc _appleputsnarf(data);
1762 50923426 2020-01-13 rsc __xputsnarf(data);
1766 50923426 2020-01-13 rsc * Send the mouse event back to the window manager.
1767 50923426 2020-01-13 rsc * So that 9term can tell rio to pop up its button3 menu.
1770 50923426 2020-01-13 rsc rpc_bouncemouse(Client *c, Mouse m)
1772 50923426 2020-01-13 rsc Xwin *w = (Xwin*)c->view;
1773 50923426 2020-01-13 rsc XButtonEvent e;
1774 50923426 2020-01-13 rsc XWindow dw;
1777 50923426 2020-01-13 rsc e.type = ButtonPress;
1778 50923426 2020-01-13 rsc e.state = 0;
1779 50923426 2020-01-13 rsc e.button = 0;
1780 50923426 2020-01-13 rsc if(m.buttons&1)
1781 50923426 2020-01-13 rsc e.button = 1;
1782 50923426 2020-01-13 rsc else if(m.buttons&2)
1783 50923426 2020-01-13 rsc e.button = 2;
1784 50923426 2020-01-13 rsc else if(m.buttons&4)
1785 50923426 2020-01-13 rsc e.button = 3;
1786 50923426 2020-01-13 rsc e.same_screen = 1;
1787 50923426 2020-01-13 rsc XTranslateCoordinates(_x.display, w->drawable,
1788 50923426 2020-01-13 rsc DefaultRootWindow(_x.display),
1789 50923426 2020-01-13 rsc m.xy.x, m.xy.y, &e.x_root, &e.y_root, &dw);
1790 50923426 2020-01-13 rsc e.root = DefaultRootWindow(_x.display);
1791 50923426 2020-01-13 rsc e.window = e.root;
1792 50923426 2020-01-13 rsc e.subwindow = None;
1793 50923426 2020-01-13 rsc e.x = e.x_root;
1794 50923426 2020-01-13 rsc e.y = e.y_root;
1795 50923426 2020-01-13 rsc #undef time
1796 50923426 2020-01-13 rsc e.time = CurrentTime;
1797 50923426 2020-01-13 rsc XUngrabPointer(_x.display, m.msec);
1798 50923426 2020-01-13 rsc XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);
1799 50923426 2020-01-13 rsc XFlush(_x.display);