Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
8097 maxcodehac 1
MODULE gr;     (* connect to libX11 *)
2
IMPORT SYSTEM, unix, out;
3
 
4
(*
5
X11 documentation in:
6
- http://tronche.com/gui/x/xlib/        an X11 reference
7
- http://www.sbin.org/doc/Xlib          an X11 tutorial (this domain has disappeared)
8
*)
9
 
10
CONST
11
        InputOutput = 1;
12
        StructureNotifyMask = 20000H;  (* input event mask *)
13
        ExposureMask = 8000H; KeyPressMask = 1; KeyReleaseMask = 2;
14
        ButtonPressMask = 4; ButtonReleaseMask = 8; (* PointerNotionMask *)
15
        ZPixmap = 2;
16
        Expose = 12;  (* X event type *) ConfigureNotify = 22; KeyPress = 2; ButtonPress = 4;
17
 
18
        EventTimeOut* = 80;    (* 0, 0, 0, 0 *)
19
        EventResize* = 81;    (* 0, w, h, 0 *)
20
        EventKeyPressed* = 82;    (* isPrintable, keyCode (X11 scan code), state, keySym (ASCII) *)
21
        EventKeyReleased* = 83;    (* 0, keyCode, state, 0 *)
22
        EventButtonPressed* = 84;    (* button, x, y, state *)
23
        EventButtonReleased* = 85;    (* button, x, y, state *)
24
        (* mouse button 1-5 = Left, Middle, Right, Scroll wheel up, Scroll wheel down *)
25
 
26
        bit64 = ORD(unix.BIT_DEPTH = 64);
27
 
28
TYPE EventPars* = ARRAY 5 OF INTEGER;
29
        XEvent = RECORD
30
                val :ARRAY 192 OF BYTE          (* union { ..., long pad[24]; } *)
31
                (* val :ARRAY 48 OF CARD32; *)
32
        END;
33
 
34
VAR ScreenWidth*, ScreenHeight* :INTEGER;
35
        winWidth*, winHeight* :INTEGER; (* draw by writing to pixel buffer: *)
36
        base*, stride* :INTEGER;                (* width, height, base ptr, stride in bytes, 32-bit RGB *)
37
        painting :BOOLEAN;
38
 
39
        libX11 :INTEGER;        (* handle to dynamic library *)
40
        XOpenDisplay :PROCEDURE [linux] (name :INTEGER) :INTEGER;
41
        XCloseDisplay :PROCEDURE [linux] (display :INTEGER);
42
        XSynchronize :PROCEDURE [linux] (display, onoff :INTEGER) :INTEGER;  (* return prev onoff *)
43
        XConnectionNumber :PROCEDURE [linux] (display :INTEGER) :INTEGER;
44
        XCreateWindow :PROCEDURE [linux] (display, parent_window, x, y, w, h, border_width, depth,
45
                class, visual, valuemask, attributes :INTEGER) :INTEGER;  (* Window *)
46
        XDefaultScreen :PROCEDURE [linux] (display :INTEGER) :INTEGER;
47
        XDefaultGC :PROCEDURE [linux] (display, screenNr :INTEGER) :INTEGER;  (* GC *)
48
        XDisplayWidth :PROCEDURE [linux] (display, screenNr :INTEGER) :INTEGER;
49
        XDisplayHeight :PROCEDURE [linux] (display, screenNr :INTEGER) :INTEGER;
50
        XDefaultVisual :PROCEDURE [linux] (display, screenNr :INTEGER) :INTEGER;  (* visual *)
51
        XDefaultRootWindow :PROCEDURE [linux] (display :INTEGER) :INTEGER;  (* Window *)
52
        XDefaultDepth :PROCEDURE [linux] (display, screenNr :INTEGER) :INTEGER;
53
        XSelectInput :PROCEDURE [linux] (display, window, event_mask :INTEGER);
54
        XMapWindow :PROCEDURE [linux] (display, window :INTEGER);
55
        XNextEvent :PROCEDURE [linux] (display, XEvent_p :INTEGER);
56
        XPending :PROCEDURE [linux] (display :INTEGER) :INTEGER;
57
        XLookupString :PROCEDURE [linux] (key_event, buffer_return, buflen, keysym_return, status_in_out :INTEGER) :INTEGER;
58
        XCreateImage :PROCEDURE [linux] (display, visual, depth, format, offset, data,
59
                width, height, bitmap_pad, bytes_per_line :INTEGER) :INTEGER; (* ptr to XImage *)
60
        XPutImage :PROCEDURE [linux] (display, window, gc, image, sx, sy, dx, dy, w, h :INTEGER);
61
 
62
        display, screen, window, gc, img :INTEGER;
63
        connectionNr :INTEGER; (* fd of X11 socket *)
64
        readX11 :unix.fd_set;  (* used by select() timeout on X11 socket *)
65
 
66
 
67
PROCEDURE getSymAdr (lib :INTEGER; name :ARRAY OF CHAR; adr :INTEGER);
68
VAR sym :INTEGER;
69
BEGIN
70
        sym := unix.dlsym (lib, SYSTEM.ADR(name[0]));
71
        IF sym = 0 THEN out.formatStr ("error: dlsym: %", name); out.nl END;
72
        ASSERT (sym # 0);
73
        SYSTEM.PUT (adr, sym)
74
END getSymAdr;
75
 
76
 
77
PROCEDURE init;
78
BEGIN
79
        display := XOpenDisplay (0);
80
        IF display = 0 THEN out.str ("error: can not open X11 display."); out.nl; out.exit(1) END;
81
        (* ri := XSynchronize (display, 1); *)
82
        connectionNr := XConnectionNumber (display); ASSERT (connectionNr < unix.FD_SETSIZE);
83
        NEW (readX11); unix.FD_ZERO(readX11); unix.FD_SET (connectionNr, readX11);
84
        screen := XDefaultScreen (display); gc := XDefaultGC (display, screen);
85
        ScreenWidth := XDisplayWidth (display, screen); ScreenHeight := XDisplayHeight (display, screen);
86
        base := unix.malloc (ScreenWidth * ScreenHeight * 4);
87
        IF base = 0 THEN
88
                out.formatInt2 ("error: can not allocate screen buffer % x %", ScreenWidth, ScreenHeight); out.nl; out.exit(1);
89
        END;
90
        stride := ScreenWidth * 4;
91
        img := XCreateImage (display, XDefaultVisual (display, screen), XDefaultDepth (display, screen),
92
                ZPixmap, 0, base, ScreenWidth, ScreenHeight, 32, 0);
93
END init;
94
 
95
 
96
PROCEDURE finish*;
97
VAR ri :INTEGER;
98
BEGIN
99
        IF display # 0 THEN XCloseDisplay(display); display := 0 END;
100
        IF libX11 # 0 THEN ri := unix.dlclose (libX11); libX11 := 0 END;
101
END finish;
102
 
103
 
104
PROCEDURE createWindow* (w, h :INTEGER);
105
VAR eventMask :INTEGER;
106
BEGIN
107
        IF (w > ScreenWidth) OR (h > ScreenHeight) THEN
108
                out.str ("error: X11.createWindow: window too large"); out.exit(1);
109
        END;
110
        ASSERT ((w >= 0) & (h >= 0));
111
        window := XCreateWindow (display, XDefaultRootWindow (display), 0, 0, w, h, 0,
112
                XDefaultDepth (display, screen), InputOutput, XDefaultVisual (display, screen), 0, 0);
113
        winWidth := w; winHeight := h;
114
        eventMask := StructureNotifyMask + ExposureMask + KeyPressMask + ButtonPressMask;
115
        XSelectInput (display, window, eventMask);
116
        XMapWindow (display, window);
117
END createWindow;
118
 
119
 
120
PROCEDURE screenBegin*;
121
        (* intended to enable future cooperation with iOS / MacOS *)
122
BEGIN
123
        ASSERT (~painting); painting := TRUE
124
END screenBegin;
125
 
126
 
127
PROCEDURE screenEnd*;
128
BEGIN
129
        ASSERT (painting);
130
        XPutImage (display, window, gc, img, 0, 0, 0, 0, winWidth, winHeight);
131
        painting := FALSE;
132
END screenEnd;
133
 
134
 
135
PROCEDURE readInt (e :XEvent; i :INTEGER) :INTEGER;
136
        (* treat XEvent byte array as int array *)
137
VAR n :INTEGER;
138
BEGIN
139
        ASSERT (i >= 0);
140
        ASSERT (i < 48);
141
        i := i * 4;
142
        n := e.val[i+3]*1000000H + e.val[i+2]*10000H + e.val[i+1]*100H + e.val[i];
143
RETURN n
144
END readInt;
145
 
146
 
147
PROCEDURE nextEvent* (msTimeOut :INTEGER; VAR ev :EventPars);
148
VAR _type, n, ri :INTEGER;
149
        event :XEvent;
150
        x, y, w, h :INTEGER;
151
        timeout :unix.timespec;
152
BEGIN
153
(* struct XEvent (64-bit):
154
any:   4 type   8 serial   4 send_event   8 display   8 window   8 window
155
expose:   40 any   4 x, y, w, h, count
156
xconfigure:   48 any   4 x, y, w, h
157
xkey / xbutton / xmotion:   48 any   8 sub_window   8 time_ms   4 x, y, x_root, y_root   4 state   4 keycode/button
158
*)
159
(* struct XEvent (32-bit):
160
any:   4 type   4 serial   4 send_event   4 display   4 window
161
expose:   20 any   4 x, y, w, h, count
162
xconfigure:   24 any   4 x, y, w, h
163
xkey / xbutton / xmotion:   24 any   4 sub_window   4 time_ms   4 x, y, x_root, y_root   4 state   4 keycode/button
164
*)
165
        _type := 0;
166
        WHILE _type = 0 DO
167
                IF (msTimeOut > 0) & (XPending(display) = 0) THEN
168
                        timeout.tv_sec := msTimeOut DIV 1000; timeout.tv_usec := (msTimeOut MOD 1000) * 1000;
169
                        ri := unix.select (connectionNr + 1, readX11, NIL, NIL, timeout); ASSERT (ri # -1);
170
                        IF ri = 0 THEN _type := EventTimeOut; ev[1] := 0; ev[2] := 0; ev[3] := 0; ev[4] := 0 END;
171
                END;
172
                IF _type = 0 THEN
173
                        XNextEvent (display, SYSTEM.ADR(event));
174
                        CASE readInt (event, 0) OF
175
                        Expose :
176
                                x := readInt (event, 5 + 5 * bit64); y := readInt (event, 6 + 5 * bit64);
177
                                w := readInt (event, 7 + 5 * bit64); h := readInt (event, 8 + 5 * bit64);
178
                                XPutImage (display, window, gc, img, x, y, x, y, w, h);
179
                        | ConfigureNotify :
180
                                w := readInt (event, 8 + 6 * bit64); h := readInt (event, 9 + 6 * bit64);
181
                                IF (w # winWidth) & (h # winHeight) THEN
182
                                        ASSERT ((w >= 0) & (h >= 0));
183
                                        IF w > ScreenWidth THEN w := ScreenWidth END;
184
                                        IF h > ScreenHeight THEN h := ScreenHeight END;
185
                                        winWidth := w; winHeight := h;
186
                                        ev[0] := EventResize; ev[1] := 0; ev[2] := w; ev[3] := h; ev[4] := 0;
187
                                END;
188
                        | KeyPress :
189
                                _type := EventKeyPressed;
190
                                x := XLookupString (SYSTEM.ADR(event), 0, 0, SYSTEM.ADR(n), 0);  (* KeySym *)
191
                                IF (n = 8) OR (n = 10) OR (n >= 32) & (n <= 126) THEN ev[1] := 1 ELSE ev[1] := 0; n := 0 END;  (* isprint *)
192
                                ev[2] := readInt (event, 13 + 8 * bit64); (* keycode *)
193
                                ev[3] := readInt (event, 12 + 8 * bit64); (* state *)
194
                                ev[4] := n;  (* KeySym *)
195
                        | ButtonPress :
196
                                _type := EventButtonPressed;
197
                                ev[1] := readInt (event, 13 + 8 * bit64); (* button *)
198
                                ev[2] := readInt (event, 8 + 8 * bit64);  (* x *)
199
                                ev[3] := readInt (event, 9 + 8 * bit64);  (* y *)
200
                                ev[4] := readInt (event, 12 + 8 * bit64); (* state *)
201
                        ELSE
202
                        END
203
                END
204
        END;
205
        ev[0] := _type
206
END nextEvent;
207
 
208
 
209
PROCEDURE clear* (color :INTEGER);   (* fill window area with color *)
210
VAR p, i, j :INTEGER;
211
BEGIN
212
        FOR j := 0 TO winHeight-1 DO
213
                p := base + j*stride;
214
                FOR i := 0 TO winWidth-1 DO SYSTEM.PUT32 (p, color); INC (p, 4) END
215
        END
216
END clear;
217
 
218
 
219
(*
220
PROCEDURE blitError (stride, x, y, w, h :INTEGER);
221
BEGIN
222
        o.formatInt ("error: screen.blit (src, %)", stride);
223
        o.formatInt2 (", %, %", x, y);
224
        o.formatInt2 (", %, %) out of bounds", w, h); o.nl;
225
        ASSERT (FALSE)
226
END blitError;
227
 
228
PROCEDURE blit* (src, srcStride, x, y, w, h :INTEGER);
229
VAR dstStride, p :INTEGER;
230
BEGIN
231
        IF (x < 0) OR (y < 0) THEN blitError (srcStride, x, y, w, h) END;
232
        IF (w <= 0) OR (h <= 0) THEN blitError (srcStride, x, y, w, h) END;
233
        IF (x + w > ScreenWidth) OR (y + h > ScreenHeight) THEN blitError (srcStride, x, y, w, h) END;
234
 
235
        dstStride := ScreenWidth - w;
236
        p := ScreenBase + y * ScreenWidth + x * 4;
237
        REPEAT
238
                SYSTEM.COPY (src, p, w);
239
                INC (src, srcStride); INC (p, dstStride); DEC (h)
240
        UNTIL h = 0
241
END blit;
242
*)
243
 
244
(*
245
PROCEDURE setPixel* (x, y, color :INTEGER);
246
VAR p :INTEGER;
247
BEGIN
248
        ASSERT ((x >= 0) & (x < ScreenWidth) & (y >= 0) & (y < ScreenHeight));
249
        screenBegin; p := base + (y*ScreenWidth + x)*4; SYSTEM.PUT32 (p, color); p := p + 4 screenEnd
250
END setPixel;
251
*)
252
 
253
(*
254
PROCEDURE loop;    (* example main loop *)
255
VAR e :EventPars;
256
        stop :BOOLEAN;
257
BEGIN
258
        createWindow (200, 200);
259
        stop := FALSE;
260
        REPEAT
261
                nextEvent (0, e);
262
                IF e[0] = EventKeyPressed THEN stop := TRUE END;
263
        UNTIL stop;
264
        XCloseDisplay (display);
265
END loop;
266
*)
267
 
268
 
269
BEGIN
270
        libX11 := unix.dlopen (SYSTEM.SADR("libX11.so.6"), unix.RTLD_LAZY); ASSERT (libX11 # 0);
271
        getSymAdr (libX11, "XOpenDisplay", SYSTEM.ADR(XOpenDisplay));
272
        getSymAdr (libX11, "XCloseDisplay", SYSTEM.ADR(XCloseDisplay));
273
        getSymAdr (libX11, "XSynchronize", SYSTEM.ADR(XSynchronize));
274
        getSymAdr (libX11, "XConnectionNumber", SYSTEM.ADR(XConnectionNumber));
275
        getSymAdr (libX11, "XCreateWindow", SYSTEM.ADR(XCreateWindow));
276
        getSymAdr (libX11, "XDefaultScreen", SYSTEM.ADR(XDefaultScreen));
277
        getSymAdr (libX11, "XDefaultGC", SYSTEM.ADR(XDefaultGC));
278
        getSymAdr (libX11, "XDisplayWidth", SYSTEM.ADR(XDisplayWidth));
279
        getSymAdr (libX11, "XDisplayHeight", SYSTEM.ADR(XDisplayHeight));
280
        getSymAdr (libX11, "XDefaultVisual", SYSTEM.ADR(XDefaultVisual));
281
        getSymAdr (libX11, "XDefaultRootWindow", SYSTEM.ADR(XDefaultRootWindow));
282
        getSymAdr (libX11, "XDefaultDepth", SYSTEM.ADR(XDefaultDepth));
283
        getSymAdr (libX11, "XSelectInput", SYSTEM.ADR(XSelectInput));
284
        getSymAdr (libX11, "XMapWindow", SYSTEM.ADR(XMapWindow));
285
        getSymAdr (libX11, "XNextEvent", SYSTEM.ADR(XNextEvent));
286
        getSymAdr (libX11, "XPending", SYSTEM.ADR(XPending));
287
        getSymAdr (libX11, "XLookupString", SYSTEM.ADR(XLookupString));
288
        getSymAdr (libX11, "XCreateImage", SYSTEM.ADR(XCreateImage));
289
        getSymAdr (libX11, "XPutImage", SYSTEM.ADR(XPutImage));
290
        init;
291
END gr.
292