sgl
diff src/wsys_x11.c @ 4:648f8604d2b2
cont. x11 module
author | John Tsiombikas <nuclear@siggraph.org> |
---|---|
date | Thu, 12 May 2011 11:04:10 +0300 |
parents | 1b6c5dadb460 |
children | 0570e27e5ebc |
line diff
1.1 --- a/src/wsys_x11.c Wed May 11 09:09:43 2011 +0300 1.2 +++ b/src/wsys_x11.c Thu May 12 11:04:10 2011 +0300 1.3 @@ -1,20 +1,43 @@ 1.4 +#include <stdlib.h> 1.5 #include <X11/Xlib.h> 1.6 #include <GL/glx.h> 1.7 +#include "sgl.h" 1.8 #include "wsys.h" 1.9 +#include "log.h" 1.10 1.11 struct window { 1.12 Window win; 1.13 GLXContext ctx; 1.14 + long evmask; 1.15 struct window *next; 1.16 }; 1.17 1.18 static int init(void); 1.19 static void shutdown(void); 1.20 -static int set_vidmode(int xsz, int ysz, int bpp); 1.21 -static int get_vidmode(int *xsz, int *ysz, int *bpp); 1.22 + 1.23 +/* video mode switching */ 1.24 +static int set_vidmode(int xsz, int ysz); 1.25 +static int get_vidmode(int *xsz, int *ysz); 1.26 + 1.27 +/* create/destroy windows */ 1.28 static int create_window(int xsz, int ysz, unsigned int flags); 1.29 +static void fill_attr(int *attr, unsigned int flags); 1.30 +static void print_visual_info(XVisualInfo *vis); 1.31 static void close_window(int id); 1.32 1.33 +/* window management */ 1.34 +static int set_active(int id); 1.35 +static int set_title(const char *str); 1.36 +static void redisplay(void); 1.37 +static void swap_buffers(void); 1.38 + 1.39 +/* event handling and friends */ 1.40 +static void set_bits(long *mask, long bits); 1.41 +static void clear_bits(long *mask, long bits); 1.42 +static void set_event(int idx, int enable); 1.43 +static int process_events(void); 1.44 + 1.45 + 1.46 static struct wsys_module ws = { 1.47 "x11-glx", 0, 1.48 init, 1.49 @@ -23,14 +46,23 @@ 1.50 get_vidmode, 1.51 create_window, 1.52 close_window, 1.53 + set_active, 1.54 + set_title, 1.55 + redisplay, 1.56 + swap_buffers, 1.57 + set_event, 1.58 + process_events, 1.59 0 1.60 }; 1.61 1.62 static Display *dpy; 1.63 +static Window root; 1.64 static int scr; 1.65 +static Atom xa_wm_prot, xa_wm_del_win; 1.66 static struct window *winlist; 1.67 +static struct window *active_win; 1.68 1.69 - 1.70 +/* this is the only exported function, everything else should be static */ 1.71 void sgl_register_x11(void) 1.72 { 1.73 sgl_register_module(&ws); 1.74 @@ -41,9 +73,14 @@ 1.75 winlist = 0; 1.76 1.77 if(!(dpy = XOpenDisplay(0))) { 1.78 + sgl_log("failed to open X display: %s\n", XDisplayName(0)); 1.79 return -1; 1.80 } 1.81 scr = DefaultScreen(dpy); 1.82 + root = RootWindow(dpy, scr); 1.83 + 1.84 + xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); 1.85 + xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 1.86 1.87 return 0; 1.88 } 1.89 @@ -55,25 +92,151 @@ 1.90 winlist = winlist->next; 1.91 1.92 glXDestroyContext(dpy, win->ctx); 1.93 - XCloseWindow(dpy, win->win); 1.94 + XDestroyWindow(dpy, win->win); 1.95 free(win); 1.96 } 1.97 XCloseDisplay(dpy); 1.98 dpy = 0; 1.99 } 1.100 1.101 -static int set_vidmode(int xsz, int ysz, int bpp) 1.102 +static int set_vidmode(int xsz, int ysz) 1.103 { 1.104 /* TODO */ 1.105 + return 0; 1.106 } 1.107 1.108 -static int get_vidmode(int *xsz, int *ysz, int *bpp) 1.109 +static int get_vidmode(int *xsz, int *ysz) 1.110 { 1.111 /* TODO */ 1.112 + return 0; 1.113 } 1.114 1.115 static int create_window(int xsz, int ysz, unsigned int flags) 1.116 { 1.117 + int attr[32]; 1.118 + Window win; 1.119 + GLXContext ctx; 1.120 + XVisualInfo *vis; 1.121 + XClassHint chint; 1.122 + XSetWindowAttributes xattr; 1.123 + unsigned int attr_valid; 1.124 + long evmask; 1.125 + struct window *wnode; 1.126 + 1.127 + if(!(wnode = malloc(sizeof *wnode))) { 1.128 + return -1; 1.129 + } 1.130 + 1.131 + fill_attr(attr, flags); 1.132 + 1.133 + if(!(vis = glXChooseVisual(dpy, scr, attr))) { 1.134 + sgl_log("failed to find a suitable visual\n"); 1.135 + free(wnode); 1.136 + return -1; 1.137 + } 1.138 + print_visual_info(vis); 1.139 + 1.140 + if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { 1.141 + sgl_log("failed to create OpenGL context\n"); 1.142 + XFree(vis); 1.143 + free(wnode); 1.144 + return -1; 1.145 + } 1.146 + 1.147 + xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); 1.148 + xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); 1.149 + attr_valid = CWColormap | CWBackPixel | CWBorderPixel; 1.150 + 1.151 + if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, 1.152 + vis->visual, attr_valid, &xattr))) { 1.153 + sgl_log("failed to create window\n"); 1.154 + glXDestroyContext(dpy, ctx); 1.155 + XFree(vis); 1.156 + free(wnode); 1.157 + return -1; 1.158 + } 1.159 + XFree(vis); 1.160 + 1.161 + evmask = StructureNotifyMask | VisibilityChangeMask; 1.162 + XSelectInput(dpy, win, evmask); 1.163 + 1.164 + XSetWMProtocols(dpy, win, &xa_wm_del_win, 1); 1.165 + 1.166 + set_title("OpenGL/X11"); 1.167 + 1.168 + chint.res_name = chint.res_class = "simplygl"; 1.169 + XSetClassHint(dpy, win, &chint); 1.170 + 1.171 + XMapWindow(dpy, win); 1.172 + 1.173 + wnode->win = win; 1.174 + wnode->ctx = ctx; 1.175 + wnode->evmask = evmask; 1.176 + wnode->next = winlist; 1.177 + winlist->next = wnode; 1.178 + 1.179 + if(!active_win) { 1.180 + set_active(win); 1.181 + } 1.182 + return win; 1.183 +} 1.184 + 1.185 +static void fill_attr(int *attr, unsigned int flags) 1.186 +{ 1.187 + int i = 0; 1.188 + 1.189 + attr[i++] = GLX_RGBA; 1.190 + attr[i++] = GLX_RED_SIZE; attr[i++] = 1; 1.191 + attr[i++] = GLX_GREEN_SIZE; attr[i++] = 1; 1.192 + attr[i++] = GLX_BLUE_SIZE; attr[i++] = 1; 1.193 + 1.194 + if(flags & SGL_DOUBLE) { 1.195 + attr[i++] = GLX_DOUBLEBUFFER; 1.196 + } 1.197 + if(flags & SGL_DEPTH) { 1.198 + attr[i++] = GLX_DEPTH_SIZE; 1.199 + attr[i++] = 1; 1.200 + } 1.201 + if(flags & SGL_STENCIL) { 1.202 + attr[i++] = GLX_STENCIL_SIZE; 1.203 + attr[i++] = 1; 1.204 + } 1.205 + if(flags & SGL_STEREO) { 1.206 + attr[i++] = GLX_STEREO; 1.207 + } 1.208 +#if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) 1.209 + if(flags & SGL_MULTISAMPLE) { 1.210 + attr[i++] = GLX_SAMPLE_BUFFERS_ARB; 1.211 + attr[i++] = 1; 1.212 + attr[i++] = GLX_SAMPLES_ARB; 1.213 + attr[i++] = 1; 1.214 + } 1.215 +#endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */ 1.216 + attr[i] = None; 1.217 +} 1.218 + 1.219 +static void print_visual_info(XVisualInfo *vis) 1.220 +{ 1.221 + int rbits, gbits, bbits, zbits, sbits, stereo, aa, samples; 1.222 + 1.223 + glXGetConfig(dpy, vis, GLX_RED_SIZE, &rbits); 1.224 + glXGetConfig(dpy, vis, GLX_GREEN_SIZE, &gbits); 1.225 + glXGetConfig(dpy, vis, GLX_BLUE_SIZE, &bbits); 1.226 + glXGetConfig(dpy, vis, GLX_DEPTH_SIZE, &zbits); 1.227 + glXGetConfig(dpy, vis, GLX_STENCIL_SIZE, &sbits); 1.228 + glXGetConfig(dpy, vis, GLX_STEREO, &stereo); 1.229 +#if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) 1.230 + glXGetConfig(dpy, vis, GLX_SAMPLE_BUFFERS_ARB, &aa); 1.231 + if(aa) { 1.232 + glXGetConfig(dpy, vis, GLX_SAMPLES_ARB, &samples); 1.233 + } else { 1.234 + samples = 1; 1.235 + } 1.236 +#endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */ 1.237 + 1.238 + sgl_log("got visual: %d%d%d d:%d s:%d", rbits, gbits, bbits, zbits, sbits); 1.239 + sgl_log(" %s", stereo ? "stereo" : "mono"); 1.240 + sgl_log(" samples/pixel: %d\n", samples); 1.241 } 1.242 1.243 static void close_window(int id) 1.244 @@ -87,7 +250,7 @@ 1.245 while(win) { 1.246 if(win->win == id) { 1.247 glXDestroyContext(dpy, win->ctx); 1.248 - XCloseWindow(dpy, win->win); 1.249 + XDestroyWindow(dpy, win->win); 1.250 prev->next = win->next; 1.251 free(win); 1.252 return; 1.253 @@ -95,3 +258,168 @@ 1.254 win = win->next; 1.255 } 1.256 } 1.257 + 1.258 +static int set_active(int id) 1.259 +{ 1.260 + struct window *win = winlist; 1.261 + 1.262 + while(win) { 1.263 + if(win->win == id) { 1.264 + if(glXMakeCurrent(dpy, win->win, win->ctx) == False) { 1.265 + sgl_log("failed to activate window %d\n", id); 1.266 + return -1; 1.267 + } 1.268 + active_win = win; 1.269 + return 0; 1.270 + } 1.271 + win = win->next; 1.272 + } 1.273 + 1.274 + sgl_log("no such window: %d\n", id); 1.275 + return -1; 1.276 +} 1.277 + 1.278 +static int set_title(const char *str) 1.279 +{ 1.280 + XTextProperty wm_name; 1.281 + 1.282 + if(!str || !active_win) { 1.283 + return -1; 1.284 + } 1.285 + XStringListToTextProperty((char**)&str, 1, &wm_name); 1.286 + XSetWMName(dpy, active_win->win, &wm_name); 1.287 + XSetWMIconName(dpy, active_win->win, &wm_name); 1.288 + XFree(wm_name.value); 1.289 + return 0; 1.290 +} 1.291 + 1.292 +static void redisplay(void) 1.293 +{ 1.294 + active_win->redisp_pending = 1; 1.295 +} 1.296 + 1.297 +static void swap_buffers(void) 1.298 +{ 1.299 + glXSwapBuffers(dpy, active_win->ctx); 1.300 +} 1.301 + 1.302 +static void set_bits(long *mask, long bits) 1.303 +{ 1.304 + *mask |= bits; 1.305 +} 1.306 + 1.307 +static void clear_bits(long *mask, long bits) 1.308 +{ 1.309 + *mask &= ~bits; 1.310 +} 1.311 + 1.312 +static void set_event(int idx, int enable) 1.313 +{ 1.314 + void (*op)(long*, long); 1.315 + op = enable ? set_bits : clear_bits; 1.316 + 1.317 + switch(idx) { 1.318 + case SGL_DISPLAY: 1.319 + op(&active_win->evmask, ExposureMask); 1.320 + break; 1.321 + 1.322 + case SGL_KEYBOARD: 1.323 + op(&active_win->evmask, KeyPressMask | KeyReleaseMask); 1.324 + break; 1.325 + 1.326 + case SGL_MOUSE: 1.327 + op(&active_win->evmask, ButtonPressMask | ButtonReleaseMask); 1.328 + break; 1.329 + 1.330 + case SGL_MOTION: 1.331 + op(&active_win->evmask, ButtonMotionMask); 1.332 + break; 1.333 + 1.334 + case SGL_PASSIVE: 1.335 + op(&active_win->evmask, PointerMotionMask); 1.336 + break; 1.337 + 1.338 + default: 1.339 + return; 1.340 + } 1.341 + 1.342 + XSelectInput(dpy, active_win->win, active_win->evmask); 1.343 +} 1.344 + 1.345 +static int process_events(void) 1.346 +{ 1.347 + XEvent xev; 1.348 + void (*func)(); 1.349 + int state; 1.350 + 1.351 + while(XPending(dpy)) { 1.352 + XNextEvent(dpy, &xev); 1.353 + 1.354 + switch(xev.type) { 1.355 + case Expose: 1.356 + if(xev.xexpose.count == 0) { 1.357 + if((func = sgl_get_callback(SGL_DISPLAY))) { 1.358 + func(); 1.359 + active_win->redisp_pending = 0; 1.360 + } 1.361 + } 1.362 + break; 1.363 + 1.364 + case MotionNotify: 1.365 + if(xev.xmotion.state) { 1.366 + func = sgl_get_callback(SGL_MOTION); 1.367 + } else { 1.368 + func = sgl_get_callback(SGL_PASSIVE); 1.369 + } 1.370 + if(func) { 1.371 + func(xev.xmotion.x, xev.xmotion.y); 1.372 + } 1.373 + break; 1.374 + 1.375 + case ButtonPress: 1.376 + if(1) { 1.377 + state = 1; 1.378 + } else { 1.379 + case ButtonRelease: 1.380 + state = 0; 1.381 + } 1.382 + if((func = sgl_get_callback(SGL_MOUSE))) { 1.383 + int bn = xev.xbutton.button - 1; 1.384 + func(bn, state, xev.xbutton.x, xev.xbutton.y); 1.385 + } 1.386 + break; 1.387 + 1.388 + case KeyPress: 1.389 + if(1) { 1.390 + state = 1; 1.391 + } else { 1.392 + case KeyRelease: 1.393 + state = 0; 1.394 + } 1.395 + if((func = sgl_get_callback(SGL_KEYBOARD))) { 1.396 + KeySym sym = XLookupKeysym(xev.xkey, 0); 1.397 + func(sym, state); 1.398 + /* XXX */ 1.399 + } 1.400 + break; 1.401 + 1.402 + case ConfigureNotify: 1.403 + if((func = sgl_get_callback(SGL_RESHAPE))) { 1.404 + func(xev.xconfigure.width, xev.xconfigure.height); 1.405 + } 1.406 + break; 1.407 + } 1.408 + 1.409 + case ClientMessage: 1.410 + if(xev.xclient.message_type == xa_wm_prot) { 1.411 + if(xev.xclient.data.l[0] == xa_wm_del_win) { 1.412 + close_window(active_win->win); 1.413 + if(!active_win) { 1.414 + return 1; 1.415 + } 1.416 + } 1.417 + } 1.418 + break; 1.419 + } 1.420 + return 0; 1.421 +}