2 * coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
3 * Understanding is not required. Only obedience.
5 * This program is free software. It comes without any warranty, to
6 * the extent permitted by applicable law. You can redistribute it
7 * and/or modify it under the terms of the Do What The Fuck You Want
8 * To Public License, Version 2, as published by Sam Hocevar. See
9 * http://sam.zoy.org/wtfpl/COPYING for more details.
16 #include <X11/keysym.h>
17 #include <X11/Xatom.h>
19 #include <X11/Xproto.h>
20 #include <X11/Xutil.h>
21 #include <X11/Xft/Xft.h>
23 #include "lstcore/k8lst.h"
24 #include "lstpl_x11.h"
28 # define dprintf(...) fprintf(stderr, __VA_ARGS__)
34 /*#define DEBUG_EVENTS*/
37 static const char *x11ObjId
= "X11Handle";
38 static const char *x11SubId
[] = {
58 static int initialized
= 0;
59 static Display
*curDisp
= NULL
;
60 static Colormap curCMap
;
62 static unsigned long blackPixel;
63 static unsigned long whitePixel;
67 static Visual
*vis
= NULL
;
68 /*static Window intrWin;*/
69 static Atom wmDeleteWindow
;
73 static XEvent eQueue
[MAX_QUEUE
];
74 static int eqHead
= 0;
75 static int eqTail
= 0;
76 static int eqCount
= 0;
78 static int aliveObjects
= 0;
81 static void deinitializeX11Subsystem (void) {
83 if (aliveObjects
== 0) {
84 /*XFreeColormap(curDisp, curCMap);*/
85 /*XDestroyWindow(curDisp, intrWin);*/
86 XCloseDisplay(curDisp
);
88 eqHead
= eqTail
= eqCount
= 0;
95 static int initializeX11Subsystem (const char *dispName
) {
97 if (aliveObjects
!= 0) return -1;
98 deinitializeX11Subsystem();
100 if (!(curDisp
= XOpenDisplay(dispName
))) return -1;
101 screen
= DefaultScreen(curDisp
);
102 rootWin
= DefaultRootWindow(curDisp
);
104 blackPixel = BlackPixel(curDisp, screen);
105 whitePixel = WhitePixel(curDisp, screen);
107 vis
= DefaultVisual(curDisp
, screen
);
108 curCMap
= DefaultColormap(curDisp
, screen
);
109 /*intrWin = XCreateSimpleWindow(curDisp, rootWin, 0, 0, 1, 1, 0, blackPixel, blackPixel);*/
110 /*curCMap = XCreateColormap(curDisp, intrWin, vis, AllocNone);*/
111 eqHead
= eqTail
= eqCount
= 0;
112 wmDeleteWindow
= XInternAtom(curDisp
, "WM_DELETE_WINDOW", False
);
133 static void deinitX11Obj (X11Object
*x11o
) {
136 if (!x11o
->dontKill
) {
137 /*dprintf("deinitializing X11 object; subtype=%s\n", x11SubId[x11o->subtype]);*/
138 /*fprintf(stderr, "deinitializing X11 object; subtype=%s\n", x11SubId[x11o->subtype]);*/
139 switch (x11o
->subtype
) {
140 case X11_WINDOW
: XDestroyWindow(curDisp
, x11o
->win
); break;
141 case X11_GC
: XFreeGC(curDisp
, x11o
->gc
); break;
142 case X11_XFTFONT
: XftFontClose(curDisp
, x11o
->font
); break;
143 case X11_XFTDRAW
: XftDrawDestroy(x11o
->xd
); break;
144 case X11_XFTCOLOR
: XftColorFree(curDisp
, vis
, curCMap
, &x11o
->tc
);
147 if (--aliveObjects
<= 0) {
150 dprintf("closing X11\n");
151 XCloseDisplay(curDisp
); curDisp
= NULL
;
154 dprintf("X11: %d objects left\n", aliveObjects
);
162 LST_FINALIZER(lpX11Finalizer
) {
163 X11Object
*x11o
= (X11Object
*)udata
;
171 static lstObject
*newX11 (X11Object
**x11o
, int subtype
) {
172 if (x11o
) *x11o
= NULL
;
173 if (subtype
< 0 || subtype
>= X11_MAXSUB
) return lstNewString("internal error");
174 lstObject
*res
= lstNewBinary(NULL
, 0);
175 X11Object
*xo
= calloc(1, sizeof(X11Object
));
176 if (!xo
) return lstNewString("out of memory");
178 xo
->subtype
= subtype
;
180 xo
->inited
= 1; /* MUST! be initialized by caller */
181 lstSetFinalizer(res
, lpX11Finalizer
, xo
);
183 if (x11o
) *x11o
= xo
;
188 static X11Object
*getX11 (lstObject
*o
) {
189 if (!LST_IS_BYTES_EX(o
) || LST_SIZE(o
) || !o
->fin
|| !o
->fin
->udata
) return NULL
;
190 X11Object
*x11o
= (X11Object
*)o
->fin
->udata
;
191 if (x11o
->type
!= x11ObjId
) return NULL
;
196 static X11Object
*getX11As (lstObject
*o
, int subtype
) {
197 X11Object
*xo
= getX11(o
);
198 if (!xo
|| !xo
->inited
|| xo
->subtype
!= subtype
) return NULL
;
203 static int getColor (lstObject
*o
, unsigned short *c
) {
205 if (LST_IS_SMALLINT(o
)) {
207 if (cc
< 0) cc
= 0; else if (cc
> 65535) cc
= 65535;
208 } else if (o
->stclass
== lstIntegerClass
) {
209 LstLInt n
= lstLIntValue(o
);
210 if (n
< 0) cc
= 0; else if (n
> 65535) cc
= 65535; else cc
= n
;
211 } else if (o
->stclass
== lstFloatClass
) {
212 LstFloat n
= lstFloatValue(o
);
213 if (n
< 0.0) cc
= 0; else if (n
>= 1.0) cc
= 65535; else cc
= (int)(n
*65535);
220 #define GETINT(dest, argn) {\
221 op = LST_PRIMARG(argn);\
222 if (LST_IS_SMALLINT(op)) (dest) = lstIntValue(op);\
223 else if (op->stclass == lstIntegerClass) (dest) = (int)lstLIntValue(op);\
224 else if (op->stclass == lstFloatClass) (dest) = (int)lstFloatValue(op);\
228 #define GETSTR(dest, argn) {\
229 op = LST_PRIMARG(argn);\
230 if (!LST_IS_BYTES_EX(op)) return NULL;\
231 (dest) = lstGetStringPtr(op);\
234 #define GETWIN(dest, argn) {\
235 op = LST_PRIMARG(argn);\
236 if (op == lstNilObj || op == lstFalseObj) (dest) = rootWin;\
238 if (!(xi = getX11As(op, X11_WINDOW))) return NULL;\
243 #define GETGC(dest, argn) {\
244 op = LST_PRIMARG(argn);\
245 if (!(xi = getX11As(op, X11_GC))) return NULL;\
249 #define GETFONT(dest, argn) {\
250 op = LST_PRIMARG(argn);\
251 if (!(xi = getX11As(op, X11_XFTFONT))) return NULL;\
255 #define GETDRAW(dest, argn) {\
256 op = LST_PRIMARG(argn);\
257 if (!(xi = getX11As(op, X11_XFTDRAW))) return NULL;\
261 #define GETTC(dest, argn) {\
262 op = LST_PRIMARG(argn);\
263 if (!(xi = getX11As(op, X11_XFTCOLOR))) return NULL;\
268 LST_PRIMFN(lpX11Do
) {
269 if (LST_PRIMARGC
< 1 || !LST_IS_SMALLINT(LST_PRIMARG(0))) return NULL
;
270 int action
= lstIntValue(LST_PRIMARG(0)), tmp
, act
;
271 lstObject
*res
= lstNilObj
, *op
;
272 const char *str
= NULL
;
273 static char buf
[128];
279 unsigned int wdt
, hgt
, border
, depth
;
290 /*fprintf(stderr, "X11Do: %d\n", action);*/
292 case 0: /* get subtype name; return string or nil */
293 if (LST_PRIMARGC
< 1) return NULL
;
294 if ((xi
= getX11(LST_PRIMARG(1))) && xi
->inited
) res
= lstNewString(x11SubId
[xi
->subtype
]);
296 case 1: /* wid2str */
297 if (LST_PRIMARGC
< 2) return NULL
;
299 sprintf(buf
, "%p", (void *)win
);
300 res
= lstNewString(buf
);
302 case 2: /* SameWID w0 w1 */
303 if (LST_PRIMARGC
< 3) return NULL
;
306 res
= win
==parent
? lstTrueObj
: lstFalseObj
;
308 case 5: /* info type */
309 if (LST_PRIMARGC
< 2 || !initialized
) return NULL
;
312 case 0: /* black pixel */
313 ll0
= XBlackPixel(curDisp
, screen
);
314 res
= lstNewInteger(ll0
);
316 case 1: /* white pixel */
317 ll0
= XWhitePixel(curDisp
, screen
);
318 res
= lstNewInteger(ll0
);
320 case 2: /* all planes */
322 res
= lstNewInteger(ll0
);
324 case 3: /* connection number */
325 ll0
= XConnectionNumber(curDisp
);
326 res
= lstNewInteger(ll0
);
329 ll0
= XDefaultDepth(curDisp
, screen
);
330 res
= lstNewInteger(ll0
);
333 ll0
= XDisplayPlanes(curDisp
, screen
);
334 res
= lstNewInteger(ll0
);
336 case 6: /* display name */
337 res
= lstNewString(XDisplayString(curDisp
));
339 case 7: /* vendor name */
340 res
= lstNewString(XServerVendor(curDisp
));
342 case 8: /* release */
343 ll0
= XVendorRelease(curDisp
);
344 res
= lstNewInteger(ll0
);
347 ll0
= XDisplayHeight(curDisp
, screen
);
348 res
= lstNewInteger(ll0
);
350 case 10: /* height */
351 ll0
= XDisplayWidth(curDisp
, screen
);
352 res
= lstNewInteger(ll0
);
354 default: return NULL
;
359 if (curDisp
!= NULL
) XFlush(curDisp
);
362 case 10: /* init [dispname]; return true or false */
363 if (LST_PRIMARGC
> 1) {
365 if (op
!= lstNilObj
) {
366 if (!LST_IS_BYTES_EX(op
)) return NULL
;
367 str
= lstGetStringPtr(op
);
370 res
= initializeX11Subsystem(str
) ? lstFalseObj
: lstTrueObj
;
372 case 11: /* deinit */
373 deinitializeX11Subsystem();
376 case 14: /* GetEvent */
377 if (!initialized
) return NULL
;
379 if (eqCount
> 0) res
= x11GetEvent();
382 case 15: /* XSelectInput window interestFlag (no other args for now) */
383 /* interestFlag is not nil, not false, not true: do not get motion events */
384 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
386 if (win
== rootWin
) return NULL
;
388 XSelectInput(curDisp
, win
, op
==lstNilObj
||op
==lstFalseObj
? 0 :
389 ButtonPressMask
| ButtonReleaseMask
| EnterWindowMask
| LeaveWindowMask
|
390 ExposureMask
| FocusChangeMask
| KeymapStateMask
| KeyPressMask
| KeyReleaseMask
|
391 StructureNotifyMask
| /*SubstructureNotifyMask |*/ VisibilityChangeMask
|
392 (op
==lstTrueObj
? ButtonMotionMask
| PointerMotionMask
: 0));
395 case 20: /* XCreateSimpleWindow parent x y wdt hgt bgcolor */
396 if (LST_PRIMARGC
< 7 || !initialized
) return NULL
;
403 win
= XCreateSimpleWindow(curDisp
, parent
, x
, y
, w
, h
, 0, bc
, bc
);
404 if (win
<= LastExtensionError
) return NULL
;
405 XSetWMProtocols(curDisp
, win
, &wmDeleteWindow
, 1);
406 res
= newX11(&xi
, X11_WINDOW
);
409 if ((wmh
= XGetWMHints(curDisp
, win
))) {
410 wmh
->flags
= InputHint
;
412 XSetWMHints(curDisp
, win
, wmh
);
415 } else XDestroyWindow(curDisp
, win
);
417 case 21: /* XDestroyWindow win */
418 if (LST_PRIMARGC
< 2 || !curDisp
) return NULL
;
419 if (!(xi
= getX11As(LST_PRIMARG(1), X11_WINDOW
))) return NULL
;
420 /*deinitX11Obj(xi);*/
421 if (xi
->inited
&& !xi
->dontKill
) {
422 XDestroyWindow(curDisp
, xi
->win
);
426 case 22: /* XStoreName win name */
427 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
429 if (LST_PRIMARGC
> 2) {
431 if (op
!= lstNilObj
) {
432 if (!LST_IS_BYTES_EX(op
)) return NULL
;
433 str
= lstGetStringPtr(op
);
436 XStoreName(curDisp
, win
, str
?str
:"");
438 case 23: /* map/unmap window: win mapflag */
439 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
442 if (op
== lstNilObj
|| op
== lstFalseObj
) XUnmapWindow(curDisp
, win
);
443 else XMapWindow(curDisp
, win
);
445 case 24: /* XGetGeometry wid type */
446 if (LST_PRIMARGC
< 3) return NULL
;
449 if (XGetGeometry(curDisp
, win
, &parent
, &x
, &y
, &wdt
, &hgt
, &border
, &depth
) == BadDrawable
) return NULL
;
454 nfo
= lstNewArray(6);
455 nfo
->data
[0] = lstNewInt((int)x
);
456 nfo
->data
[1] = lstNewInt((int)y
);
457 nfo
->data
[2] = lstNewInt((int)wdt
);
458 nfo
->data
[3] = lstNewInt((int)hgt
);
459 nfo
->data
[4] = lstNewInt((int)border
);
460 nfo
->data
[5] = lstNewInt((int)depth
);
464 case 1: res
= lstNewInteger((int)x
); break;
465 case 2: res
= lstNewInteger((int)y
); break;
466 case 3: res
= lstNewInteger((int)wdt
); break;
467 case 4: res
= lstNewInteger((int)hgt
); break;
468 case 5: res
= lstNewInteger((int)border
); break;
469 case 6: res
= lstNewInteger((int)depth
); break;
470 default: return NULL
;
473 case 25: /* XSetWindowBackground win color */
474 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
478 XSetWindowBackground(curDisp
, win
, upix
);
480 case 26: /* XClearWindow wid */
481 if (LST_PRIMARGC
< 2 || !initialized
) return NULL
;
483 XClearWindow(curDisp
, win
);
485 case 27: /* window movement: type wid nx ny [nw nh] */
486 if (LST_PRIMARGC
< 5 || !initialized
) return NULL
;
493 XMoveWindow(curDisp
, win
, x
, y
);
496 XResizeWindow(curDisp
, win
, x
, y
);
499 if (LST_PRIMARGC
< 7) return NULL
;
502 XMoveResizeWindow(curDisp
, win
, x
, y
, w
, h
);
504 default: return NULL
;
507 case 28: /* InputFocus win[true: query] */
508 if (LST_PRIMARGC
< 2 || !initialized
) return NULL
;
510 if (op
== lstNilObj
|| op
== lstFalseObj
) win
= None
;
511 else if (op
== lstTrueObj
) {
512 if (XGetInputFocus(curDisp
, &win
, &tmp
)) break;
513 if (win
!= None
&& win
!= PointerRoot
) {
514 res
= newX11(&xi
, X11_WINDOW
);
519 if (!(xi
= getX11As(op
, X11_WINDOW
))) return NULL
;
521 /*fprintf(stderr, "SETTING FOCUS TO: %p\n", (void *)win);*/
523 XSetInputFocus(curDisp
, win
, RevertToParent
, CurrentTime
);
527 case 30: /* XCreateGC window [fgcolor] */
528 if (LST_PRIMARGC
< 2 || !initialized
) return NULL
;
530 if (LST_PRIMARGC
> 2) {
533 tmp
= XWhitePixel(curDisp
, screen
);
535 gc
= XCreateGC(curDisp
, win
, 0, NULL
);
536 XSetForeground(curDisp
, gc
, tmp
);
537 res
= newX11(&xi
, X11_GC
);
538 if (xi
) xi
->gc
= gc
; else XFreeGC(curDisp
, gc
);
540 case 31: /* XFreeGC gc */
541 if (LST_PRIMARGC
< 2 || !curDisp
) return NULL
;
542 if (!(xi
= getX11As(LST_PRIMARG(1), X11_GC
))) return NULL
;
545 case 32: /* XNewColor r g b */
546 if (LST_PRIMARGC
< 4 || !initialized
) return NULL
;
547 if (getColor(LST_PRIMARG(1), &cc
.red
)) return NULL
;
548 if (getColor(LST_PRIMARG(2), &cc
.green
)) return NULL
;
549 if (getColor(LST_PRIMARG(3), &cc
.blue
)) return NULL
;
550 Status rc
= XAllocColor(curDisp
, curCMap
, &cc
);
554 res
= lstNewInteger(tmp
);
557 case 33: /* XFreeColor int */
558 if (LST_PRIMARGC
< 2 || !curDisp
) return NULL
;
561 tmp
= XFreeColors(curDisp
, curCMap
, &upix
, 1, 0);
563 if (--aliveObjects
<= 0 && !initialized
) {
564 XCloseDisplay(curDisp
); curDisp
= NULL
;
568 case 34: /* XSetColor gc color [backflag] */
569 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
572 if (LST_PRIMARGC
> 3) op
= LST_PRIMARG(3); else op
= lstNilObj
;
573 if (op
!= lstFalseObj
&& op
!= lstNilObj
) XSetBackground(curDisp
, gc
, tmp
);
574 else XSetForeground(curDisp
, gc
, tmp
);
576 case 35: /* XSetLineAttr gc width line cap join */
577 if (LST_PRIMARGC
< 6 || !initialized
) return NULL
;
585 case 1: tmp
= LineDoubleDash
; break;
586 case 2: tmp
= LineOnOffDash
; break;
587 default: tmp
= LineSolid
; break;
590 case 0: x
= CapNotLast
; break;
591 /*case 1: x = CapButt; break;*/
592 case 2: x
= CapRound
; break;
593 case 3: x
= CapProjecting
; break;
594 default: x
= CapButt
; break;
597 case 1: y
= JoinRound
; break;
598 case 2: y
= JoinBevel
; break;
599 default: y
= JoinMiter
; break;
601 XSetLineAttributes(curDisp
, gc
, w
, tmp
, x
, y
);
604 case 40: /* XDrawPoint wid gc x y */
605 if (LST_PRIMARGC
< 5 || !initialized
) return NULL
;
610 XDrawPoint(curDisp
, win
, gc
, x
, y
);
612 case 41: /* XDrawLine wid gc x0 y0 x1 y1 */
613 if (LST_PRIMARGC
< 7 || !initialized
) return NULL
;
620 XDrawLine(curDisp
, win
, gc
, x0
, y0
, x1
, y1
);
622 case 42: /* XDrawRect wid gc x0 y0 wdt hgt */
623 if (LST_PRIMARGC
< 7 || !initialized
) return NULL
;
630 XDrawRectangle(curDisp
, win
, gc
, x
, y
, w
, h
);
632 case 43: /* XFillRect wid gc x y w h */
633 if (LST_PRIMARGC
< 7 || !initialized
) return NULL
;
640 XFillRectangle(curDisp
, win
, gc
, x
, y
, w
, h
);
643 case 50: /* XftFontOpen name */
644 if (LST_PRIMARGC
< 2 || !initialized
) return NULL
;
646 font
= XftFontOpenName(curDisp
, screen
, str
);
647 if (!font
) return NULL
;
648 res
= newX11(&xi
, X11_XFTFONT
);
649 if (xi
) xi
->font
= font
; else XftFontClose(curDisp
, font
);
651 case 51: /* XftFontClose font */
652 if (LST_PRIMARGC
< 2 || !curDisp
) return NULL
;
653 if (!(xi
= getX11As(LST_PRIMARG(1), X11_XFTFONT
))) return NULL
;
656 case 52: /* XftDrawCreate win */
657 if (LST_PRIMARGC
< 2 || !initialized
) return NULL
;
659 xd
= XftDrawCreate(curDisp
, win
, vis
, curCMap
);
660 if (!xd
) return NULL
;
661 res
= newX11(&xi
, X11_XFTDRAW
);
662 if (xi
) xi
->xd
= xd
; else XftDrawDestroy(xd
);
664 case 53: /* XftDrawDestroy drw */
665 if (LST_PRIMARGC
< 2 || !curDisp
) return NULL
;
666 if (!(xi
= getX11As(LST_PRIMARG(1), X11_XFTDRAW
))) return NULL
;
669 case 54: /* XNewTextColor r g b */
670 if (LST_PRIMARGC
< 4 || !initialized
) return NULL
;
671 if (getColor(LST_PRIMARG(1), &rcc
.red
)) return NULL
;
672 if (getColor(LST_PRIMARG(2), &rcc
.green
)) return NULL
;
673 if (getColor(LST_PRIMARG(3), &rcc
.blue
)) return NULL
;
675 XftColorAllocValue(curDisp
, vis
, curCMap
, &rcc
, &tc
);
676 res
= newX11(&xi
, X11_XFTCOLOR
);
677 if (xi
) xi
->tc
= tc
; else XftColorFree(curDisp
, vis
, curCMap
, &tc
);
679 case 55: /* XFreeTextColor tc */
680 if (LST_PRIMARGC
< 2 || !curDisp
) return NULL
;
681 if (!(xi
= getX11As(LST_PRIMARG(1), X11_XFTCOLOR
))) return NULL
;
684 case 56: /* XftFontDraw drw color font x y text */
685 if (LST_PRIMARGC
< 7 || !initialized
) return NULL
;
692 XftDrawStringUtf8(xd
, &tc
, font
, x
, y
, (const XftChar8
*)(str
), strlen(str
)); /*FIXME: use object size here*/
694 case 57: /* XftTextExtents font text [what] */
695 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
698 XftTextExtentsUtf8(curDisp
, font
, (const XftChar8
*)(str
), strlen(str
), &info
); /*FIXME: use object size here*/
699 if (LST_PRIMARGC
> 3) {
700 op
= LST_PRIMARG(3); if (!LST_IS_SMALLINT(op
)) return NULL
;
701 switch (lstIntValue(op
)) {
702 case 0: goto xftTextExtentsGetAll
;
703 case 1: res
= lstNewInt((int)info
.width
); break;
704 case 2: res
= lstNewInt((int)info
.height
); break;
705 case 3: res
= lstNewInt(info
.x
); break;
706 case 4: res
= lstNewInt(info
.y
); break;
707 case 5: res
= lstNewInt(info
.xOff
); break;
708 case 6: res
= lstNewInt(info
.yOff
); break;
709 default: return NULL
;
712 xftTextExtentsGetAll
: (void)0;
715 nfo
= lstNewArray(6);
716 nfo
->data
[0] = lstNewInt((int)info
.width
);
717 nfo
->data
[1] = lstNewInt((int)info
.height
);
718 nfo
->data
[2] = lstNewInt(info
.x
);
719 nfo
->data
[3] = lstNewInt(info
.y
);
720 nfo
->data
[4] = lstNewInt(info
.xOff
);
721 nfo
->data
[5] = lstNewInt(info
.yOff
);
726 case 80: /* withdraw/iconify win true:withdraw */
727 if (LST_PRIMARGC
< 3 || !initialized
) return NULL
;
730 if (op
== lstTrueObj
) XWithdrawWindow(curDisp
, win
, screen
);
731 else XIconifyWindow(curDisp
, win
, screen
);
733 case 81: /* wmhints win hintid val ... */
734 if (LST_PRIMARGC
< 4 || !initialized
) return NULL
;
736 if (win
== rootWin
) return NULL
;
739 wmh
= XGetWMHints(curDisp
, win
);
740 if (!wmh
) return NULL
;
742 case 0: /* input type */
743 wmh
->flags
|= InputHint
;
744 wmh
->input
= op
==lstNilObj
||op
==lstFalseObj
? False
: True
;
746 case 1: /* urgency */
747 if (op
== lstNilObj
|| op
== lstFalseObj
) wmh
->flags
&= ~(XUrgencyHint
);
748 else wmh
->flags
|= XUrgencyHint
;
750 default: XFree(wmh
); wmh
= NULL
; res
= NULL
; break;
753 XSetWMHints(curDisp
, win
, wmh
);
757 default: return NULL
;
759 /*if (curDisp) XFlush(curDisp);*/
764 void x11LoopStep (void) {
765 if (!curDisp
) return;
766 /*x11_fd = ConnectionNumber(dis);*/
767 while (XPending(curDisp
) > 0) {
768 if (eqCount
>= MAX_QUEUE
) return;
769 XNextEvent(curDisp
, &eQueue
[eqTail
++]);
770 if (eqTail
== MAX_QUEUE
) eqTail
= 0;
776 int x11HasEvent (void) {
785 } dbgEventNames
[] = {
789 {"ButtonRelease", 5},
795 {"KeymapNotify", 11},
797 {"GraphicsExpose", 13},
799 {"VisibilityNotify", 15},
800 {"CreateNotify", 16},
801 {"DestroyNotify", 17},
805 {"ReparentNotify", 21},
806 {"ConfigureNotify", 22},
807 {"ConfigureRequest", 23},
808 {"GravityNotify", 24},
809 {"ResizeRequest", 25},
810 {"CirculateNotify", 26},
811 {"CirculateRequest", 27},
812 {"PropertyNotify", 28},
813 {"SelectionClear", 29},
814 {"SelectionRequest", 30},
815 {"SelectionNotify", 31},
816 {"ColormapNotify", 32},
817 {"ClientMessage", 33},
818 {"MappingNotify", 34},
819 {"GenericEvent", 35},
824 const char *dbgEentName (int id
) {
826 for (f
= 0; dbgEventNames
[f
].name
; ++f
) {
827 if (dbgEventNames
[f
].id
== id
) return dbgEventNames
[f
].name
;
829 return "UnknownEventType";
836 lstObject
*sym
; /* not need to register as root, 'cause symbols will not disappear */
838 /* 0*/{"MotionNotify", 0},
839 /* 1*/{"ButtonPress", 0},
840 /* 2*/{"ButtonRelease", 0},
841 /* 3*/{"EnterNotify", 0},
842 /* 4*/{"LeaveNotify", 0},
844 /* 6*/{"FocusIn", 0},
845 /* 7*/{"FocusOut", 0},
846 /* 8*/{"KeymapNotify", 0},
847 /* 9*/{"KeyPress", 0},
848 /*10*/{"KeyRelease", 0},
849 /*11*/{"MapNotify", 0},
850 /*12*/{"UnmapNotify", 0},
851 /*13*/{"VisibilityNotify", 0},
852 /*14*/{"DestroyNotify", 0},
853 /*15*/{"ConfigureNotify", 0},
855 /*16*/{"WMCloseRequest", 0},
859 lstObject
*x11GetEvent (void) {
863 while (eqCount
> 0) {
865 XEvent
*e
= &eQueue
[eqHead
++];
866 if (eqHead
== MAX_QUEUE
) eqHead
= 0;
869 fprintf(stderr
, "GETEVENT: event=%d; win=%p (%s)\n", e
->type
, (void *)e
->xany
.window
, dbgEentName(e
->type
));
871 win
= newX11(&xi
, X11_WINDOW
);
873 xi
->win
= e
->xany
.window
;
876 XMotionEvent
*ee
= (XMotionEvent
*)e
;
877 /* type, window, x, y, keymask, xroot, yroot */
878 res
= lstNewArray(7);
879 res
->data
[0] = eventNames
[0].sym
;
881 res
->data
[2] = lstNewInteger(ee
->x
);
882 res
->data
[3] = lstNewInteger(ee
->y
);
883 res
->data
[4] = lstNewInteger(ee
->state
);
884 res
->data
[5] = lstNewInteger(ee
->x_root
);
885 res
->data
[6] = lstNewInteger(ee
->y_root
);
889 case ButtonRelease
: {
890 /* type, window, x, y, keymask, xroot, yroot, button */
891 XButtonEvent
*ee
= (XButtonEvent
*)e
;
892 res
= lstNewArray(8);
893 res
->data
[0] = e
->type
==ButtonPress
? eventNames
[1].sym
: eventNames
[2].sym
;
895 res
->data
[2] = lstNewInteger(ee
->x
);
896 res
->data
[3] = lstNewInteger(ee
->y
);
897 res
->data
[4] = lstNewInteger(ee
->state
);
898 res
->data
[5] = lstNewInteger(ee
->x_root
);
899 res
->data
[6] = lstNewInteger(ee
->y_root
);
900 res
->data
[7] = lstNewInteger(ee
->button
);
905 /* type window focus */
906 XCrossingEvent
*ee
= (XCrossingEvent
*)e
;
907 res
= lstNewArray(3);
908 res
->data
[0] = e
->type
==EnterNotify
? eventNames
[3].sym
: eventNames
[4].sym
;
910 res
->data
[2] = ee
->focus
? lstTrueObj
: lstFalseObj
;
914 /* type window x y wdt hgt count */
915 XExposeEvent
*ee
= (XExposeEvent
*)e
;
916 res
= lstNewArray(7);
917 res
->data
[0] = eventNames
[5].sym
;
919 res
->data
[2] = lstNewInteger(ee
->x
);
920 res
->data
[3] = lstNewInteger(ee
->y
);
921 res
->data
[4] = lstNewInteger(ee
->width
);
922 res
->data
[5] = lstNewInteger(ee
->height
);
923 res
->data
[6] = lstNewInteger(ee
->count
);
929 /*XFocusChangeEvent *ee = (XFocusChangeEvent *)e;*/
930 res
= lstNewArray(2);
931 res
->data
[0] = e
->type
==FocusIn
? eventNames
[6].sym
: eventNames
[7].sym
;
937 res = lstNewArray(2);
938 res->data[0] = eventNames[8].sym;
947 static char keyName
[32];
949 /* type window x, y, keymask, xroot, yroot, key */
950 XKeyEvent
*ee
= (XKeyEvent
*)e
;
951 res
= lstNewArray(9);
952 res
->data
[0] = e
->type
==KeyPress
? eventNames
[9].sym
: eventNames
[10].sym
;
954 res
->data
[2] = lstNewInteger(ee
->x
);
955 res
->data
[3] = lstNewInteger(ee
->y
);
956 res
->data
[4] = lstNewInteger(ee
->state
);
957 res
->data
[5] = lstNewInteger(ee
->x_root
);
958 res
->data
[6] = lstNewInteger(ee
->y_root
);
959 res
->data
[7] = lstNewInteger(ee
->keycode
);
960 int xslen
= XLookupString(ee
, keyName
, sizeof(keyName
), &key
, 0);
961 if (xslen
< 0) xslen
= 0;
962 keyName
[xslen
] = '\0';
963 /*fprintf(stderr, "[%s]\n", keyName);*/
965 res
->data
[8] = lstNewChar(keyName
[0]);
967 res
->data
[8] = lstNewString(keyName
);
974 /*XMapEvent *ee = (XMapEvent *)e;*/
975 res
= lstNewArray(2);
976 res
->data
[0] = eventNames
[11].sym
;
982 /*XMapEvent *ee = (XMapEvent *)e;*/
983 res
= lstNewArray(2);
984 res
->data
[0] = eventNames
[12].sym
;
988 case VisibilityNotify
: {
989 /* type, window visflag */
990 XVisibilityEvent
*ee
= (XVisibilityEvent
*)e
;
991 res
= lstNewArray(3);
992 res
->data
[0] = eventNames
[13].sym
;
994 res
->data
[2] = ee
->state
==VisibilityFullyObscured
? lstNilObj
:
995 (ee
->state
==VisibilityPartiallyObscured
? lstFalseObj
: lstTrueObj
);
998 case DestroyNotify
: {
1000 /*XMapEvent *ee = (XMapEvent *)e;*/
1001 res
= lstNewArray(2);
1002 res
->data
[0] = eventNames
[14].sym
;
1006 case ConfigureNotify
: {
1008 XConfigureEvent
*ee
= (XConfigureEvent
*)e
;
1009 res
= lstNewArray(6);
1010 res
->data
[0] = eventNames
[15].sym
;
1012 res
->data
[2] = lstNewInteger(ee
->x
);
1013 res
->data
[3] = lstNewInteger(ee
->y
);
1014 res
->data
[4] = lstNewInteger(ee
->width
);
1015 res
->data
[5] = lstNewInteger(ee
->height
);
1018 case ClientMessage
: {
1019 XClientMessageEvent
*ee
= (XClientMessageEvent
*)e
;
1020 /* Window Manager or something else */
1021 if ((Atom
)ee
->data
.l
[0] == wmDeleteWindow
) {
1022 res
= lstNewArray(2);
1023 res
->data
[0] = eventNames
[16].sym
;
1036 static const LSTExtPrimitiveTable primTbl
[] = {
1037 {"X11Do", lpX11Do
, NULL
},
1041 void lstInitX11Library (void) {
1043 for (f
= 0; eventNames
[f
].name
; ++f
) {
1044 eventNames
[f
].sym
= lstNewSymbol(eventNames
[f
].name
);
1045 lstAddStaticRoot(&eventNames
[f
].sym
);
1049 void lstInitPrimitivesX11 (void) {
1050 lstRegisterExtPrimitiveTable(primTbl
);