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