nuclear@4: #include nuclear@3: #include nuclear@3: #include nuclear@4: #include "sgl.h" nuclear@3: #include "wsys.h" nuclear@4: #include "log.h" nuclear@3: nuclear@3: struct window { nuclear@3: Window win; nuclear@3: GLXContext ctx; nuclear@4: long evmask; nuclear@3: struct window *next; nuclear@3: }; nuclear@3: nuclear@3: static int init(void); nuclear@3: static void shutdown(void); nuclear@4: nuclear@4: /* video mode switching */ nuclear@4: static int set_vidmode(int xsz, int ysz); nuclear@4: static int get_vidmode(int *xsz, int *ysz); nuclear@4: nuclear@4: /* create/destroy windows */ nuclear@3: static int create_window(int xsz, int ysz, unsigned int flags); nuclear@4: static void fill_attr(int *attr, unsigned int flags); nuclear@4: static void print_visual_info(XVisualInfo *vis); nuclear@3: static void close_window(int id); nuclear@3: nuclear@4: /* window management */ nuclear@4: static int set_active(int id); nuclear@4: static int set_title(const char *str); nuclear@4: static void redisplay(void); nuclear@4: static void swap_buffers(void); nuclear@4: nuclear@4: /* event handling and friends */ nuclear@4: static void set_bits(long *mask, long bits); nuclear@4: static void clear_bits(long *mask, long bits); nuclear@4: static void set_event(int idx, int enable); nuclear@4: static int process_events(void); nuclear@4: nuclear@4: nuclear@3: static struct wsys_module ws = { nuclear@3: "x11-glx", 0, nuclear@3: init, nuclear@3: shutdown, nuclear@3: set_vidmode, nuclear@3: get_vidmode, nuclear@3: create_window, nuclear@3: close_window, nuclear@4: set_active, nuclear@4: set_title, nuclear@4: redisplay, nuclear@4: swap_buffers, nuclear@4: set_event, nuclear@4: process_events, nuclear@3: 0 nuclear@3: }; nuclear@3: nuclear@3: static Display *dpy; nuclear@4: static Window root; nuclear@3: static int scr; nuclear@4: static Atom xa_wm_prot, xa_wm_del_win; nuclear@3: static struct window *winlist; nuclear@4: static struct window *active_win; nuclear@3: nuclear@4: /* this is the only exported function, everything else should be static */ nuclear@3: void sgl_register_x11(void) nuclear@3: { nuclear@3: sgl_register_module(&ws); nuclear@3: } nuclear@3: nuclear@3: static int init(void) nuclear@3: { nuclear@3: winlist = 0; nuclear@3: nuclear@3: if(!(dpy = XOpenDisplay(0))) { nuclear@4: sgl_log("failed to open X display: %s\n", XDisplayName(0)); nuclear@3: return -1; nuclear@3: } nuclear@3: scr = DefaultScreen(dpy); nuclear@4: root = RootWindow(dpy, scr); nuclear@4: nuclear@4: xa_wm_prot = XInternAtom(dpy, "WM_PROTOCOLS", False); nuclear@4: xa_wm_del_win = XInternAtom(dpy, "WM_DELETE_WINDOW", False); nuclear@3: nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: static void shutdown(void) nuclear@3: { nuclear@3: while(winlist) { nuclear@3: struct window *win = winlist; nuclear@3: winlist = winlist->next; nuclear@3: nuclear@3: glXDestroyContext(dpy, win->ctx); nuclear@4: XDestroyWindow(dpy, win->win); nuclear@3: free(win); nuclear@3: } nuclear@3: XCloseDisplay(dpy); nuclear@3: dpy = 0; nuclear@3: } nuclear@3: nuclear@4: static int set_vidmode(int xsz, int ysz) nuclear@3: { nuclear@3: /* TODO */ nuclear@4: return 0; nuclear@3: } nuclear@3: nuclear@4: static int get_vidmode(int *xsz, int *ysz) nuclear@3: { nuclear@3: /* TODO */ nuclear@4: return 0; nuclear@3: } nuclear@3: nuclear@3: static int create_window(int xsz, int ysz, unsigned int flags) nuclear@3: { nuclear@4: int attr[32]; nuclear@4: Window win; nuclear@4: GLXContext ctx; nuclear@4: XVisualInfo *vis; nuclear@4: XClassHint chint; nuclear@4: XSetWindowAttributes xattr; nuclear@4: unsigned int attr_valid; nuclear@4: long evmask; nuclear@4: struct window *wnode; nuclear@4: nuclear@4: if(!(wnode = malloc(sizeof *wnode))) { nuclear@4: return -1; nuclear@4: } nuclear@4: nuclear@4: fill_attr(attr, flags); nuclear@4: nuclear@4: if(!(vis = glXChooseVisual(dpy, scr, attr))) { nuclear@4: sgl_log("failed to find a suitable visual\n"); nuclear@4: free(wnode); nuclear@4: return -1; nuclear@4: } nuclear@4: print_visual_info(vis); nuclear@4: nuclear@4: if(!(ctx = glXCreateContext(dpy, vis, 0, True))) { nuclear@4: sgl_log("failed to create OpenGL context\n"); nuclear@4: XFree(vis); nuclear@4: free(wnode); nuclear@4: return -1; nuclear@4: } nuclear@4: nuclear@4: xattr.background_pixel = xattr.border_pixel = BlackPixel(dpy, scr); nuclear@4: xattr.colormap = XCreateColormap(dpy, root, vis->visual, AllocNone); nuclear@4: attr_valid = CWColormap | CWBackPixel | CWBorderPixel; nuclear@4: nuclear@4: if(!(win = XCreateWindow(dpy, root, 0, 0, xsz, ysz, 0, vis->depth, InputOutput, nuclear@4: vis->visual, attr_valid, &xattr))) { nuclear@4: sgl_log("failed to create window\n"); nuclear@4: glXDestroyContext(dpy, ctx); nuclear@4: XFree(vis); nuclear@4: free(wnode); nuclear@4: return -1; nuclear@4: } nuclear@4: XFree(vis); nuclear@4: nuclear@4: evmask = StructureNotifyMask | VisibilityChangeMask; nuclear@4: XSelectInput(dpy, win, evmask); nuclear@4: nuclear@4: XSetWMProtocols(dpy, win, &xa_wm_del_win, 1); nuclear@4: nuclear@4: set_title("OpenGL/X11"); nuclear@4: nuclear@4: chint.res_name = chint.res_class = "simplygl"; nuclear@4: XSetClassHint(dpy, win, &chint); nuclear@4: nuclear@4: XMapWindow(dpy, win); nuclear@4: nuclear@4: wnode->win = win; nuclear@4: wnode->ctx = ctx; nuclear@4: wnode->evmask = evmask; nuclear@4: wnode->next = winlist; nuclear@4: winlist->next = wnode; nuclear@4: nuclear@4: if(!active_win) { nuclear@4: set_active(win); nuclear@4: } nuclear@4: return win; nuclear@4: } nuclear@4: nuclear@4: static void fill_attr(int *attr, unsigned int flags) nuclear@4: { nuclear@4: int i = 0; nuclear@4: nuclear@4: attr[i++] = GLX_RGBA; nuclear@4: attr[i++] = GLX_RED_SIZE; attr[i++] = 1; nuclear@4: attr[i++] = GLX_GREEN_SIZE; attr[i++] = 1; nuclear@4: attr[i++] = GLX_BLUE_SIZE; attr[i++] = 1; nuclear@4: nuclear@4: if(flags & SGL_DOUBLE) { nuclear@4: attr[i++] = GLX_DOUBLEBUFFER; nuclear@4: } nuclear@4: if(flags & SGL_DEPTH) { nuclear@4: attr[i++] = GLX_DEPTH_SIZE; nuclear@4: attr[i++] = 1; nuclear@4: } nuclear@4: if(flags & SGL_STENCIL) { nuclear@4: attr[i++] = GLX_STENCIL_SIZE; nuclear@4: attr[i++] = 1; nuclear@4: } nuclear@4: if(flags & SGL_STEREO) { nuclear@4: attr[i++] = GLX_STEREO; nuclear@4: } nuclear@4: #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) nuclear@4: if(flags & SGL_MULTISAMPLE) { nuclear@4: attr[i++] = GLX_SAMPLE_BUFFERS_ARB; nuclear@4: attr[i++] = 1; nuclear@4: attr[i++] = GLX_SAMPLES_ARB; nuclear@4: attr[i++] = 1; nuclear@4: } nuclear@4: #endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */ nuclear@4: attr[i] = None; nuclear@4: } nuclear@4: nuclear@4: static void print_visual_info(XVisualInfo *vis) nuclear@4: { nuclear@4: int rbits, gbits, bbits, zbits, sbits, stereo, aa, samples; nuclear@4: nuclear@4: glXGetConfig(dpy, vis, GLX_RED_SIZE, &rbits); nuclear@4: glXGetConfig(dpy, vis, GLX_GREEN_SIZE, &gbits); nuclear@4: glXGetConfig(dpy, vis, GLX_BLUE_SIZE, &bbits); nuclear@4: glXGetConfig(dpy, vis, GLX_DEPTH_SIZE, &zbits); nuclear@4: glXGetConfig(dpy, vis, GLX_STENCIL_SIZE, &sbits); nuclear@4: glXGetConfig(dpy, vis, GLX_STEREO, &stereo); nuclear@4: #if defined(GLX_VERSION_1_4) || defined(GLX_ARB_multisample) nuclear@4: glXGetConfig(dpy, vis, GLX_SAMPLE_BUFFERS_ARB, &aa); nuclear@4: if(aa) { nuclear@4: glXGetConfig(dpy, vis, GLX_SAMPLES_ARB, &samples); nuclear@4: } else { nuclear@4: samples = 1; nuclear@4: } nuclear@4: #endif /* defined GLX_VERSION_1_4 || GLX_ARB_multisample */ nuclear@4: nuclear@4: sgl_log("got visual: %d%d%d d:%d s:%d", rbits, gbits, bbits, zbits, sbits); nuclear@4: sgl_log(" %s", stereo ? "stereo" : "mono"); nuclear@4: sgl_log(" samples/pixel: %d\n", samples); nuclear@3: } nuclear@3: nuclear@3: static void close_window(int id) nuclear@3: { nuclear@3: struct window dummy, *win, *prev; nuclear@3: dummy.next = winlist; nuclear@3: nuclear@3: prev = &dummy; nuclear@3: win = prev->next; nuclear@3: nuclear@3: while(win) { nuclear@3: if(win->win == id) { nuclear@3: glXDestroyContext(dpy, win->ctx); nuclear@4: XDestroyWindow(dpy, win->win); nuclear@3: prev->next = win->next; nuclear@3: free(win); nuclear@3: return; nuclear@3: } nuclear@3: win = win->next; nuclear@3: } nuclear@3: } nuclear@4: nuclear@4: static int set_active(int id) nuclear@4: { nuclear@4: struct window *win = winlist; nuclear@4: nuclear@4: while(win) { nuclear@4: if(win->win == id) { nuclear@4: if(glXMakeCurrent(dpy, win->win, win->ctx) == False) { nuclear@4: sgl_log("failed to activate window %d\n", id); nuclear@4: return -1; nuclear@4: } nuclear@4: active_win = win; nuclear@4: return 0; nuclear@4: } nuclear@4: win = win->next; nuclear@4: } nuclear@4: nuclear@4: sgl_log("no such window: %d\n", id); nuclear@4: return -1; nuclear@4: } nuclear@4: nuclear@4: static int set_title(const char *str) nuclear@4: { nuclear@4: XTextProperty wm_name; nuclear@4: nuclear@4: if(!str || !active_win) { nuclear@4: return -1; nuclear@4: } nuclear@4: XStringListToTextProperty((char**)&str, 1, &wm_name); nuclear@4: XSetWMName(dpy, active_win->win, &wm_name); nuclear@4: XSetWMIconName(dpy, active_win->win, &wm_name); nuclear@4: XFree(wm_name.value); nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@4: static void redisplay(void) nuclear@4: { nuclear@4: active_win->redisp_pending = 1; nuclear@4: } nuclear@4: nuclear@4: static void swap_buffers(void) nuclear@4: { nuclear@4: glXSwapBuffers(dpy, active_win->ctx); nuclear@4: } nuclear@4: nuclear@4: static void set_bits(long *mask, long bits) nuclear@4: { nuclear@4: *mask |= bits; nuclear@4: } nuclear@4: nuclear@4: static void clear_bits(long *mask, long bits) nuclear@4: { nuclear@4: *mask &= ~bits; nuclear@4: } nuclear@4: nuclear@4: static void set_event(int idx, int enable) nuclear@4: { nuclear@4: void (*op)(long*, long); nuclear@4: op = enable ? set_bits : clear_bits; nuclear@4: nuclear@4: switch(idx) { nuclear@4: case SGL_DISPLAY: nuclear@4: op(&active_win->evmask, ExposureMask); nuclear@4: break; nuclear@4: nuclear@4: case SGL_KEYBOARD: nuclear@4: op(&active_win->evmask, KeyPressMask | KeyReleaseMask); nuclear@4: break; nuclear@4: nuclear@4: case SGL_MOUSE: nuclear@4: op(&active_win->evmask, ButtonPressMask | ButtonReleaseMask); nuclear@4: break; nuclear@4: nuclear@4: case SGL_MOTION: nuclear@4: op(&active_win->evmask, ButtonMotionMask); nuclear@4: break; nuclear@4: nuclear@4: case SGL_PASSIVE: nuclear@4: op(&active_win->evmask, PointerMotionMask); nuclear@4: break; nuclear@4: nuclear@4: default: nuclear@4: return; nuclear@4: } nuclear@4: nuclear@4: XSelectInput(dpy, active_win->win, active_win->evmask); nuclear@4: } nuclear@4: nuclear@4: static int process_events(void) nuclear@4: { nuclear@4: XEvent xev; nuclear@4: void (*func)(); nuclear@4: int state; nuclear@4: nuclear@4: while(XPending(dpy)) { nuclear@4: XNextEvent(dpy, &xev); nuclear@4: nuclear@4: switch(xev.type) { nuclear@4: case Expose: nuclear@4: if(xev.xexpose.count == 0) { nuclear@4: if((func = sgl_get_callback(SGL_DISPLAY))) { nuclear@4: func(); nuclear@4: active_win->redisp_pending = 0; nuclear@4: } nuclear@4: } nuclear@4: break; nuclear@4: nuclear@4: case MotionNotify: nuclear@4: if(xev.xmotion.state) { nuclear@4: func = sgl_get_callback(SGL_MOTION); nuclear@4: } else { nuclear@4: func = sgl_get_callback(SGL_PASSIVE); nuclear@4: } nuclear@4: if(func) { nuclear@4: func(xev.xmotion.x, xev.xmotion.y); nuclear@4: } nuclear@4: break; nuclear@4: nuclear@4: case ButtonPress: nuclear@4: if(1) { nuclear@4: state = 1; nuclear@4: } else { nuclear@4: case ButtonRelease: nuclear@4: state = 0; nuclear@4: } nuclear@4: if((func = sgl_get_callback(SGL_MOUSE))) { nuclear@4: int bn = xev.xbutton.button - 1; nuclear@4: func(bn, state, xev.xbutton.x, xev.xbutton.y); nuclear@4: } nuclear@4: break; nuclear@4: nuclear@4: case KeyPress: nuclear@4: if(1) { nuclear@4: state = 1; nuclear@4: } else { nuclear@4: case KeyRelease: nuclear@4: state = 0; nuclear@4: } nuclear@4: if((func = sgl_get_callback(SGL_KEYBOARD))) { nuclear@4: KeySym sym = XLookupKeysym(xev.xkey, 0); nuclear@4: func(sym, state); nuclear@4: /* XXX */ nuclear@4: } nuclear@4: break; nuclear@4: nuclear@4: case ConfigureNotify: nuclear@4: if((func = sgl_get_callback(SGL_RESHAPE))) { nuclear@4: func(xev.xconfigure.width, xev.xconfigure.height); nuclear@4: } nuclear@4: break; nuclear@4: } nuclear@4: nuclear@4: case ClientMessage: nuclear@4: if(xev.xclient.message_type == xa_wm_prot) { nuclear@4: if(xev.xclient.data.l[0] == xa_wm_del_win) { nuclear@4: close_window(active_win->win); nuclear@4: if(!active_win) { nuclear@4: return 1; nuclear@4: } nuclear@4: } nuclear@4: } nuclear@4: break; nuclear@4: } nuclear@4: return 0; nuclear@4: }