rev |
line source |
nuclear@4
|
1 #include <stdio.h>
|
nuclear@4
|
2 #include <stdlib.h>
|
nuclear@4
|
3 #include <X11/Xlib.h>
|
nuclear@4
|
4 #include <X11/Xutil.h>
|
nuclear@4
|
5 #include "wsys.h"
|
nuclear@4
|
6 #include "vku.h"
|
nuclear@4
|
7
|
nuclear@4
|
8 struct callbacks {
|
nuclear@4
|
9 void (*display)(void);
|
nuclear@4
|
10 void (*reshape)(int, int);
|
nuclear@4
|
11 void (*keyboard)(int, int);
|
nuclear@4
|
12 void (*mouse)(int, int, int, int);
|
nuclear@4
|
13 void (*motion)(int, int);
|
nuclear@4
|
14 void (*passive)(int, int);
|
nuclear@4
|
15 };
|
nuclear@4
|
16
|
nuclear@4
|
17 enum {
|
nuclear@4
|
18 QUIT = 1,
|
nuclear@4
|
19 RESHAPE = 2,
|
nuclear@4
|
20 REDISPLAY = 4
|
nuclear@4
|
21 };
|
nuclear@4
|
22
|
nuclear@4
|
23 static void proc_event(XEvent *ev);
|
nuclear@4
|
24
|
nuclear@4
|
25 static Display *dpy;
|
nuclear@4
|
26 static Window win;
|
nuclear@4
|
27 static Atom xa_wm_delete;
|
nuclear@4
|
28 static int win_width, win_height;
|
nuclear@4
|
29 static int win_mapped;
|
nuclear@4
|
30 static unsigned int evmask = StructureNotifyMask | ExposureMask;
|
nuclear@4
|
31 static unsigned int pending;
|
nuclear@4
|
32 static struct callbacks cb;
|
nuclear@4
|
33
|
nuclear@4
|
34 int wsys_create_window(int xsz, int ysz)
|
nuclear@4
|
35 {
|
nuclear@4
|
36 int i, scr, num_visuals;
|
nuclear@4
|
37 Window root_win;
|
nuclear@4
|
38 Visual *vis = 0;
|
nuclear@4
|
39 XSetWindowAttributes xattr;
|
nuclear@4
|
40 unsigned int xattr_mask;
|
nuclear@4
|
41 XVisualInfo *vinf, vinf_match;
|
nuclear@4
|
42
|
nuclear@4
|
43 if(!(dpy = XOpenDisplay(0))) {
|
nuclear@4
|
44 fprintf(stderr, "failed to open connection to the X server\n");
|
nuclear@4
|
45 return -1;
|
nuclear@4
|
46 }
|
nuclear@4
|
47 scr = DefaultScreen(dpy);
|
nuclear@4
|
48 root_win = RootWindow(dpy, scr);
|
nuclear@4
|
49
|
nuclear@4
|
50 xa_wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
nuclear@4
|
51
|
nuclear@4
|
52 vinf_match.screen = scr;
|
nuclear@4
|
53 vinf_match.depth = 24;
|
nuclear@4
|
54 vinf_match.class = TrueColor;
|
nuclear@4
|
55
|
nuclear@4
|
56 if(!(vinf = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &vinf_match, &num_visuals))) {
|
nuclear@4
|
57 fprintf(stderr, "failed to retrieve matching visuals\n");
|
nuclear@4
|
58 XCloseDisplay(dpy);
|
nuclear@4
|
59 return -1;
|
nuclear@4
|
60 }
|
nuclear@4
|
61
|
nuclear@4
|
62 for(i=0; i<num_visuals; i++) {
|
nuclear@4
|
63 if(vku_xlib_usable_visual(dpy, vinf[i].visualid)) {
|
nuclear@4
|
64 vis = vinf[i].visual;
|
nuclear@4
|
65 break;
|
nuclear@4
|
66 }
|
nuclear@4
|
67 }
|
nuclear@4
|
68 if(!vis) {
|
nuclear@4
|
69 fprintf(stderr, "failed to find approprate visual\n");
|
nuclear@4
|
70 XFree(vinf);
|
nuclear@4
|
71 XCloseDisplay(dpy);
|
nuclear@4
|
72 return -1;
|
nuclear@4
|
73 }
|
nuclear@4
|
74
|
nuclear@4
|
75 xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr);
|
nuclear@4
|
76 xattr.colormap = XCreateColormap(dpy, root_win, vis, AllocNone);
|
nuclear@4
|
77 xattr_mask = CWBackPixel | CWBorderPixel | CWColormap;
|
nuclear@4
|
78
|
nuclear@4
|
79 if(!(win = XCreateWindow(dpy, root_win, 0, 0, xsz, ysz, 0, 24, InputOutput, vis, xattr_mask, &xattr))) {
|
nuclear@4
|
80 fprintf(stderr, "failed to create X window\n");
|
nuclear@4
|
81 XFree(vinf);
|
nuclear@4
|
82 XCloseDisplay(dpy);
|
nuclear@4
|
83 return -1;
|
nuclear@4
|
84 }
|
nuclear@4
|
85 XFree(vinf);
|
nuclear@4
|
86
|
nuclear@4
|
87 XSelectInput(dpy, win, evmask);
|
nuclear@4
|
88 XSetWMProtocols(dpy, win, &xa_wm_delete, 1);
|
nuclear@4
|
89
|
nuclear@4
|
90 wsys_set_window_title("X11 window");
|
nuclear@4
|
91 XMapWindow(dpy, win);
|
nuclear@4
|
92
|
nuclear@4
|
93 win_width = xsz;
|
nuclear@4
|
94 win_height = ysz;
|
nuclear@4
|
95 pending = RESHAPE | REDISPLAY;
|
nuclear@4
|
96
|
nuclear@4
|
97 return 0;
|
nuclear@4
|
98 }
|
nuclear@4
|
99
|
nuclear@4
|
100 void wsys_destroy_window(void)
|
nuclear@4
|
101 {
|
nuclear@4
|
102 if(dpy) {
|
nuclear@4
|
103 if(win) {
|
nuclear@4
|
104 XDestroyWindow(dpy, win);
|
nuclear@4
|
105 win = 0;
|
nuclear@4
|
106 }
|
nuclear@4
|
107 XCloseDisplay(dpy);
|
nuclear@4
|
108 dpy = 0;
|
nuclear@4
|
109 }
|
nuclear@4
|
110 }
|
nuclear@4
|
111
|
nuclear@4
|
112 void wsys_get_window_size(int *xsz, int *ysz)
|
nuclear@4
|
113 {
|
nuclear@4
|
114 *xsz = win_width;
|
nuclear@4
|
115 *ysz = win_height;
|
nuclear@4
|
116 }
|
nuclear@4
|
117
|
nuclear@4
|
118 void wsys_set_window_title(const char *title)
|
nuclear@4
|
119 {
|
nuclear@4
|
120 XTextProperty text;
|
nuclear@4
|
121 XStringListToTextProperty((char**)&title, 1, &text);
|
nuclear@4
|
122 XSetWMName(dpy, win, &text);
|
nuclear@4
|
123 XSetWMIconName(dpy, win, &text);
|
nuclear@4
|
124 XFree(text.value);
|
nuclear@4
|
125 }
|
nuclear@4
|
126
|
nuclear@4
|
127 void wsys_display_callback(void (*func)(void))
|
nuclear@4
|
128 {
|
nuclear@4
|
129 cb.display = func;
|
nuclear@4
|
130 }
|
nuclear@4
|
131
|
nuclear@4
|
132 void wsys_reshape_callback(void (*func)(int, int))
|
nuclear@4
|
133 {
|
nuclear@4
|
134 cb.reshape = func;
|
nuclear@4
|
135 }
|
nuclear@4
|
136
|
nuclear@4
|
137 void wsys_keyboard_callback(void (*func)(int, int))
|
nuclear@4
|
138 {
|
nuclear@4
|
139 cb.keyboard = func;
|
nuclear@4
|
140 if(func) {
|
nuclear@4
|
141 evmask |= KeyPressMask | KeyReleaseMask;
|
nuclear@4
|
142 } else {
|
nuclear@4
|
143 evmask &= ~(KeyPressMask | KeyReleaseMask);
|
nuclear@4
|
144 }
|
nuclear@4
|
145 if(win) {
|
nuclear@4
|
146 XSelectInput(dpy, win, evmask);
|
nuclear@4
|
147 }
|
nuclear@4
|
148 }
|
nuclear@4
|
149
|
nuclear@4
|
150 void wsys_mouse_callback(void (*func)(int, int, int, int))
|
nuclear@4
|
151 {
|
nuclear@4
|
152 cb.mouse = func;
|
nuclear@4
|
153 if(func) {
|
nuclear@4
|
154 evmask |= ButtonPressMask | ButtonReleaseMask;
|
nuclear@4
|
155 } else {
|
nuclear@4
|
156 evmask &= ~(ButtonPressMask | ButtonReleaseMask);
|
nuclear@4
|
157 }
|
nuclear@4
|
158 if(win) {
|
nuclear@4
|
159 XSelectInput(dpy, win, evmask);
|
nuclear@4
|
160 }
|
nuclear@4
|
161 }
|
nuclear@4
|
162
|
nuclear@4
|
163 void wsys_motion_callback(void (*func)(int, int))
|
nuclear@4
|
164 {
|
nuclear@4
|
165 cb.motion = func;
|
nuclear@4
|
166 if(func) {
|
nuclear@4
|
167 evmask |= ButtonMotionMask;
|
nuclear@4
|
168 } else {
|
nuclear@4
|
169 evmask &= ~ButtonMotionMask;
|
nuclear@4
|
170 }
|
nuclear@4
|
171 if(win) {
|
nuclear@4
|
172 XSelectInput(dpy, win, evmask);
|
nuclear@4
|
173 }
|
nuclear@4
|
174 }
|
nuclear@4
|
175
|
nuclear@4
|
176 void wsys_passive_motion_callback(void (*func)(int, int))
|
nuclear@4
|
177 {
|
nuclear@4
|
178 cb.passive = func;
|
nuclear@4
|
179 if(func) {
|
nuclear@4
|
180 evmask |= PointerMotionMask;
|
nuclear@4
|
181 } else {
|
nuclear@4
|
182 evmask &= ~PointerMotionMask;
|
nuclear@4
|
183 }
|
nuclear@4
|
184 if(win) {
|
nuclear@4
|
185 XSelectInput(dpy, win, evmask);
|
nuclear@4
|
186 }
|
nuclear@4
|
187 }
|
nuclear@4
|
188
|
nuclear@4
|
189 void wsys_swap_buffers(void)
|
nuclear@4
|
190 {
|
nuclear@4
|
191 /* TODO */
|
nuclear@4
|
192 }
|
nuclear@4
|
193
|
nuclear@4
|
194 void wsys_redisplay(void)
|
nuclear@4
|
195 {
|
nuclear@4
|
196 pending |= REDISPLAY;
|
nuclear@4
|
197 }
|
nuclear@4
|
198
|
nuclear@4
|
199 void wsys_quit(void)
|
nuclear@4
|
200 {
|
nuclear@4
|
201 pending |= QUIT;
|
nuclear@4
|
202 }
|
nuclear@4
|
203
|
nuclear@4
|
204 int wsys_process_events(int mode)
|
nuclear@4
|
205 {
|
nuclear@4
|
206 XEvent xev;
|
nuclear@4
|
207
|
nuclear@4
|
208 if(pending & RESHAPE) {
|
nuclear@4
|
209 if(cb.reshape) {
|
nuclear@4
|
210 cb.reshape(win_width, win_height);
|
nuclear@4
|
211 }
|
nuclear@4
|
212 pending &= ~RESHAPE;
|
nuclear@4
|
213 }
|
nuclear@4
|
214
|
nuclear@4
|
215 if(mode == WSYS_BLOCKING) {
|
nuclear@4
|
216 XNextEvent(dpy, &xev);
|
nuclear@4
|
217 proc_event(&xev);
|
nuclear@4
|
218 if(pending & QUIT) return -1;
|
nuclear@4
|
219 }
|
nuclear@4
|
220
|
nuclear@4
|
221 while(XPending(dpy)) {
|
nuclear@4
|
222 XNextEvent(dpy, &xev);
|
nuclear@4
|
223 proc_event(&xev);
|
nuclear@4
|
224 if(pending & QUIT) return -1;
|
nuclear@4
|
225 }
|
nuclear@4
|
226
|
nuclear@4
|
227 if(pending & REDISPLAY && win_mapped) {
|
nuclear@4
|
228 pending &= ~REDISPLAY;
|
nuclear@4
|
229 if(cb.display) {
|
nuclear@4
|
230 cb.display();
|
nuclear@4
|
231 }
|
nuclear@4
|
232 }
|
nuclear@4
|
233 return 0;
|
nuclear@4
|
234 }
|
nuclear@4
|
235
|
nuclear@4
|
236 static void proc_event(XEvent *ev)
|
nuclear@4
|
237 {
|
nuclear@4
|
238 switch(ev->type) {
|
nuclear@4
|
239 case MapNotify:
|
nuclear@4
|
240 win_mapped = 1;
|
nuclear@4
|
241 break;
|
nuclear@4
|
242
|
nuclear@4
|
243 case UnmapNotify:
|
nuclear@4
|
244 win_mapped = 0;
|
nuclear@4
|
245 break;
|
nuclear@4
|
246
|
nuclear@4
|
247 case ClientMessage:
|
nuclear@4
|
248 if(ev->xclient.data.l[0] == xa_wm_delete) {
|
nuclear@4
|
249 pending |= QUIT;
|
nuclear@4
|
250 }
|
nuclear@4
|
251 break;
|
nuclear@4
|
252
|
nuclear@4
|
253 case ConfigureNotify:
|
nuclear@4
|
254 if(ev->xconfigure.width != win_width || ev->xconfigure.height != win_height) {
|
nuclear@4
|
255 win_width = ev->xconfigure.width;
|
nuclear@4
|
256 win_height = ev->xconfigure.height;
|
nuclear@4
|
257 pending |= RESHAPE;
|
nuclear@4
|
258 }
|
nuclear@4
|
259 break;
|
nuclear@4
|
260
|
nuclear@4
|
261 case Expose:
|
nuclear@4
|
262 if(ev->xexpose.count == 0) {
|
nuclear@4
|
263 pending |= REDISPLAY;
|
nuclear@4
|
264 }
|
nuclear@4
|
265 break;
|
nuclear@4
|
266
|
nuclear@4
|
267 case KeyPress:
|
nuclear@4
|
268 case KeyRelease:
|
nuclear@4
|
269 if(cb.keyboard) {
|
nuclear@4
|
270 KeySym sym;
|
nuclear@4
|
271 char str[16];
|
nuclear@4
|
272 XLookupString(&ev->xkey, str, sizeof str, &sym, 0);
|
nuclear@4
|
273 cb.keyboard(sym & 0xff, ev->type == KeyPress ? 1 : 0);
|
nuclear@4
|
274 }
|
nuclear@4
|
275 break;
|
nuclear@4
|
276
|
nuclear@4
|
277 case ButtonPress:
|
nuclear@4
|
278 case ButtonRelease:
|
nuclear@4
|
279 if(cb.mouse) {
|
nuclear@4
|
280 int bn = ev->xbutton.button - Button1;
|
nuclear@4
|
281 int pressed = ev->type == ButtonPress ? 1 : 0;
|
nuclear@4
|
282 cb.mouse(bn, pressed, ev->xbutton.x, ev->xbutton.y);
|
nuclear@4
|
283 }
|
nuclear@4
|
284 break;
|
nuclear@4
|
285
|
nuclear@4
|
286 case MotionNotify:
|
nuclear@4
|
287 if(ev->xmotion.state & 0x1f00) {
|
nuclear@4
|
288 if(cb.motion) {
|
nuclear@4
|
289 cb.motion(ev->xmotion.x, ev->xmotion.y);
|
nuclear@4
|
290 }
|
nuclear@4
|
291 } else {
|
nuclear@4
|
292 if(cb.passive) {
|
nuclear@4
|
293 cb.passive(ev->xmotion.x, ev->xmotion.y);
|
nuclear@4
|
294 }
|
nuclear@4
|
295 }
|
nuclear@4
|
296 break;
|
nuclear@4
|
297 }
|
nuclear@4
|
298 }
|