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